[Helix-client-dev] CR/CN: Implemented -xmlout program option, added support for -xmlin pictures [GMPMetaEditor branch]
Petar Basic <[email protected]> Mon, 18 Jan 2010 21:44:28 +0100
| Newsgroups | gmane.comp.multimedia.helix.devel |
|---|---|
| Message-ID | <[email protected]> |
Modified by: pbasic at real.com Date: 2010/01/18 Project: GMPMetaEditor (meta3gp.exe) Synopsis: Implemented -xmlout program option, added support for -xmlin pictures [GMPMetaEditor branch] Details: 1.) -xmlout option writes extracted or injected metadata into the specified XML file. 2.) Added support for XML input file elements: "albums/album/image/fileName", "albums/album/image/fileName2". Files Modified: datatype/common/util/pub/metautil.h datatype/common/util/metautil.cpp datatype/tools/dtdriver/apps/meta3gp/HXXmlInputParser.h datatype/tools/dtdriver/apps/meta3gp/HXXmlInputParser.cpp datatype/tools/dtdriver/apps/meta3gp/main.cpp Platforms and Profiles Affected: All Image Size and Heap Use impact: None Platforms and Profiles Build Verified: system id: win32-i386-vc7, sunos-5.10-sparc-studio11 profile: helix-client-all-defines Platforms and Profiles Functionality Verified: x86 Windows XP SP2 Sparc SunOS 5.10 Branch: GMPMetaEditor Copyright assignment: I am a RealNetworks employee or contractor. _______________________________________________ Helix-client-dev mailing list [email protected] http://lists.helixcommunity.org/mailman/listinfo/helix-client-dev
datatype_common_util.diff
(application/octet-stream, 23.3 KB)
Index: metautil.cpp
===================================================================
RCS file: /cvsroot/datatype/common/util/metautil.cpp,v
retrieving revision 1.13
diff -d -H -w -U30 -r1.13 metautil.cpp
--- metautil.cpp 6 Jan 2010 17:38:26 -0000 1.13
+++ metautil.cpp 18 Jan 2010 21:24:09 -0000
@@ -2777,86 +2777,86 @@
res = HXR_OK;
}
fclose(fp);
}
return res;
}
MetaInfo::MetaInfo()
{
Clear();
}
MetaInfo::~MetaInfo()
{
ClearKeywords();
ClearPictures();
}
MetaInfo::MetaInfo(const MetaInfo& rhs)
{
*this = rhs;
}
MetaInfo& MetaInfo::operator=(const MetaInfo& rhs)
{
Clear();
UpdateItems(rhs);
return *this;
}
-void MetaInfo::Dump(UINT32 metaInfoSetFlags)
+void MetaInfo::Dump(UINT32 metaInfoSetFlags) const
{
// Generic
if(metaInfoSetFlags & METAINFO_SET_GENERIC)
{
Dump(_GENERIC_META_INFO_TITLE_KEY, m_stringItems[StringMetaItem_Title]);
Dump(_GENERIC_META_INFO_COMPOSER_KEY, m_stringItems[StringMetaItem_Composer]);
Dump(_GENERIC_META_INFO_COPYRIGHT_KEY, m_stringItems[StringMetaItem_Copyright]);
Dump(_GENERIC_META_INFO_DESCRIPTION_KEY, m_stringItems[StringMetaItem_Description]);
Dump(_GENERIC_META_INFO_ARTIST_KEY, m_stringItems[StringMetaItem_Artist]);
Dump(_GENERIC_META_INFO_GENRE_KEY, m_stringItems[StringMetaItem_Genre]);
Dump(_GENERIC_META_INFO_ALBUM_KEY, m_stringItems[StringMetaItem_Album]);
Dump(_GENERIC_META_INFO_UITS_KEY, m_stringItems[StringMetaItem_UITSData], FALSE);
Dump(_GENERIC_META_INFO_TRACK_NUMBER_KEY, m_ulongItems[UIntMetaItem_TrackNumber],
m_ulongItemValidFlags[UIntMetaItem_TrackNumber]);
Dump(_GENERIC_META_INFO_RECORDING_YEAR_KEY, m_ulongItems[UIntMetaItem_RecordingYear],
m_ulongItemValidFlags[UIntMetaItem_RecordingYear]);
for(UINT32 i = 0; i < GetPictureCount(); i++)
{
printf(_GENERIC_META_INFO_PICTURE_KEY": ", int(i));
ID3Tools::APICFrame* pFrame = GetPictureByIndex(i);
if(pFrame)
{
- printf("PictureType=%d, MimeType=%s, PictureData=%d bytes\n",
+ printf("PictureType=%d, MimeType=%s, PictureSize=%d bytes\n",
pFrame->GetPictureType(),
(const char*)pFrame->GetMimeType(),
pFrame->GetPictureDataSize());
}
}
}
// iTunes
if(metaInfoSetFlags & METAINFO_SET_ITUNES_SPECIFIC)
{
Dump(_ITUNES_META_INFO_TRACK_SUBTITLE_KEY, m_stringItems[StringMetaItem_TrackSubtitle]);
Dump(_ITUNES_META_INFO_GENERATOR_TOOL_KEY, m_stringItems[StringMetaItem_GeneratorTool]);
Dump(_ITUNES_META_INFO_ENCODED_BY_KEY, m_stringItems[StringMetaItem_EncodedBy]);
Dump(_ITUNES_META_INFO_GROUPING_KEY, m_stringItems[StringMetaItem_Grouping]);
Dump(_ITUNES_META_INFO_ALBUM_ARTIST_KEY, m_stringItems[StringMetaItem_AlbumArtist]);
Dump(_ITUNES_META_INFO_LYRICS_KEY, m_stringItems[StringMetaItem_Lyrics]);
Dump(_ITUNES_META_INFO_BEATS_PER_MINUTE_KEY, m_ulongItems[UIntMetaItem_BeatsPerMinute],
m_ulongItemValidFlags[UIntMetaItem_BeatsPerMinute]);
Dump(_ITUNES_META_INFO_PART_OF_COMPILATION_KEY, m_ulongItems[UIntMetaItem_PartOfCompilation],
m_ulongItemValidFlags[UIntMetaItem_PartOfCompilation]);
Dump(_ITUNES_META_INFO_EXPLICIT_CONTENT_KEY, m_ulongItems[UIntMetaItem_ExplicitContent],
m_ulongItemValidFlags[UIntMetaItem_ExplicitContent]);
Dump(_ITUNES_META_INFO_TRACK_COUNT_KEY, m_ulongItems[UIntMetaItem_TrackCount],
m_ulongItemValidFlags[UIntMetaItem_TrackCount]);
Dump(_ITUNES_META_INFO_DISC_NUMBER_KEY, m_ulongItems[UIntMetaItem_DiscNumber],
m_ulongItemValidFlags[UIntMetaItem_DiscNumber]);
Dump(_ITUNES_META_INFO_DISC_COUNT_KEY, m_ulongItems[UIntMetaItem_DiscCount],
m_ulongItemValidFlags[UIntMetaItem_DiscCount]);
}
@@ -2864,60 +2864,206 @@
if(metaInfoSetFlags & METAINFO_SET_3GPP_SPECIFIC)
{
Dump(_3GPP_META_INFO_GLOBAL_LANGUAGE_ENCODING_KEY, m_stringItems[StringMetaItem_GlobalLanguageEncoding]);
Dump(_3GPP_META_INFO_RATING_ENTITY_KEY, m_stringItems[StringMetaItem_RatingEntity]);
Dump(_3GPP_META_INFO_RATING_CRITERIA_KEY, m_stringItems[StringMetaItem_RatingCriteria]);
Dump(_3GPP_META_INFO_RATING_INFO_KEY, m_stringItems[StringMetaItem_RatingInfo]);
Dump(_3GPP_META_INFO_CLASSIFICATION_ENTITY_KEY, m_stringItems[StringMetaItem_ClassificationEntity]);
Dump(_3GPP_META_INFO_CLASSIFICATION_TABLE_KEY, m_ulongItems[UIntMetaItem_ClassificationTable],
m_ulongItemValidFlags[UIntMetaItem_ClassificationTable]);
Dump(_3GPP_META_INFO_CLASSIFICATION_INFO_KEY, m_stringItems[StringMetaItem_ClassificationInfo]);
Dump(_3GPP_META_INFO_LOCATION_NAME_KEY, m_stringItems[StringMetaItem_LocationName]);
Dump(_3GPP_META_INFO_LOCATION_ASTRONOMICAL_BODY_KEY, m_stringItems[StringMetaItem_LocationAstronomicalBody]);
Dump(_3GPP_META_INFO_LOCATION_ADDITIONAL_NOTES_KEY, m_stringItems[StringMetaItem_LocationAdditionalNotes]);
Dump(_3GPP_META_INFO_LOCATION_ROLE_KEY, m_ulongItems[UIntMetaItem_LocationRole],
m_ulongItemValidFlags[UIntMetaItem_LocationRole]);
Dump(_3GPP_META_INFO_LOCATION_LONGITUDE_KEY, m_stringItems[StringMetaItem_LocationLongitude]);
Dump(_3GPP_META_INFO_LOCATION_LATITUDE_KEY, m_stringItems[StringMetaItem_LocationLatitude]);
Dump(_3GPP_META_INFO_LOCATION_ALTITUDE_KEY, m_stringItems[StringMetaItem_LocationAltitude]);
for(UINT32 i = 0; i < GetKeywordCount(); i++)
{
printf(_3GPP_META_INFO_KEYWORD_KEY": ", int(i));
EncodedString kwd;
GetKeyword(i, kwd);
kwd.Dump();
printf("\n");
}
}
}
+void MetaInfo::DumpElementToXMLString(CHXString& out, const CHXString& ws,
+ const EncodedString& src, const CHXString& elementName,
+ const CHXString& attributes)
+{
+ if(!src.IsEmpty() || !attributes.IsEmpty())
+ {
+ out += ws + "<" + elementName;
+
+ if(!attributes.IsEmpty())
+ {
+ out += " " + attributes;
+ }
+
+ if(src.IsEmpty())
+ {
+ out += "/>";
+ }
+ else
+ {
+ out += ">";
+ out += src.GetData();
+ out += "</" + elementName + ">";
+ }
+ out += "\n";
+ }
+}
+
+void MetaInfo::DumpStringItemToXMLString(CHXString& out, const CHXString& ws,
+ eStringMetaItem item, const CHXString& elementName,
+ const CHXString& attributes) const
+{
+ DumpElementToXMLString(out, ws, m_stringItems[item], elementName, attributes);
+}
+
+void MetaInfo::DumpUIntToXMLString(CHXString& out, const CHXString& ws,
+ UINT32 src, const CHXString& elementName,
+ const CHXString& attributes)
+{
+ CHXString s;
+ s.AppendULONG(src);
+ EncodedString es((const char*)s);
+ DumpElementToXMLString(out, ws, es, elementName, attributes);
+}
+
+void MetaInfo::DumpUIntItemToXMLString(CHXString& out, const CHXString& ws,
+ eUIntMetaItem item, const CHXString& elementName,
+ const CHXString& attributes) const
+{
+ if(m_ulongItemValidFlags[item])
+ {
+ DumpUIntToXMLString(out, ws, m_ulongItems[item], elementName, attributes);
+ }
+}
+
+void MetaInfo::DumpToXMLString(CHXString& out,
+ const CHXString& uitsFilename, const CHXString& picOutFilenamePrefix,
+ UINT32 metaInfoSetFlags, UINT32 tabLevel, UINT32 tabWidth) const
+{
+ CHXString ws0 = CHXString(' ', tabLevel * tabWidth);
+ CHXString ws1 = CHXString(' ', (tabLevel + 1) * tabWidth);
+
+ out += ws0 + "<metadata>\n";
+
+ // Generic
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Title, "title");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Composer, "composer");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Copyright, "copyright");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Description, "description");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Artist, "artist");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Genre, "genre");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Album, "album");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_TrackNumber, "trackNumber");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_RecordingYear, "year");
+
+ // UITS
+ if(!m_stringItems[StringMetaItem_UITSData].IsEmpty())
+ {
+ CHXString attUits = "size=\"";
+ attUits.AppendULONG(m_stringItems[StringMetaItem_UITSData].GetByteLength());
+ attUits += "\"";
+ if(!uitsFilename.IsEmpty())
+ {
+ attUits += " path=\"" + uitsFilename + "\"";
+ }
+ DumpElementToXMLString(out, ws1, EncodedString(), "uits", attUits);
+ }
+
+ // Pictures
+ for(UINT32 i = 0; i < GetPictureCount(); i++)
+ {
+ ID3Tools::APICFrame* pFrame = GetPictureByIndex(i);
+ if(pFrame)
+ {
+ CHXString attPic = "size=\"";
+ attPic.AppendULONG(pFrame->GetPictureDataSize());
+ attPic += "\" pictureType=\"";
+ attPic.AppendULONG(pFrame->GetPictureType());
+ attPic += "\" type=\"" + pFrame->GetMimeType() + "\"";
+ if(!picOutFilenamePrefix.IsEmpty())
+ {
+ attPic += " path=\"" + MakePictureFilename(*pFrame, i, picOutFilenamePrefix) + "\"";
+ }
+ DumpElementToXMLString(out, ws1, EncodedString(), "picture", attPic);
+ }
+ }
+
+ // iTunes
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_TrackSubtitle, "subtitle");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_GeneratorTool, "generatorTool");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_EncodedBy, "encodedBy");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Grouping, "grouping");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_AlbumArtist, "albumArtist");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_Lyrics, "lyrics");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_BeatsPerMinute, "bpm");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_PartOfCompilation, "partOfCompilation");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_ExplicitContent, "explicitContent");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_TrackCount, "trackCount");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_DiscNumber, "discNumber");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_DiscCount, "discCount");
+
+ // 3GPP
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_GlobalLanguageEncoding, "language");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_RatingEntity, "ratingEntity");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_RatingCriteria, "ratingCriteria");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_RatingInfo, "ratingInfo");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_ClassificationEntity, "classificationEntity");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_ClassificationTable, "classificationTable");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_ClassificationInfo, "classificationInfo");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_LocationName, "locationName");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_LocationAstronomicalBody, "locationAstronomicalBody");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_LocationAdditionalNotes, "locationAdditionalNotes");
+ DumpUIntItemToXMLString(out, ws1, UIntMetaItem_LocationRole, "locationRole");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_LocationLongitude, "locationLongitude");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_LocationLatitude, "locationLatitude");
+ DumpStringItemToXMLString(out, ws1, StringMetaItem_LocationAltitude, "locationAltitude");
+
+ for(UINT32 i = 0; i < GetKeywordCount(); i++)
+ {
+ EncodedString kwd;
+ GetKeyword(i, kwd);
+ DumpElementToXMLString(out, ws1, kwd, "keyword");
+ }
+
+ out += ws0 + "</metadata>\n";
+}
+
void MetaInfo::Clear()
{
for(int iStrItem = StringMetaItem_Begin_; iStrItem < StringMetaItem_End_; iStrItem++)
{
m_stringItems[iStrItem].Clear();
}
for(int iUIntItem = UIntMetaItem_Begin_; iUIntItem < UIntMetaItem_End_; iUIntItem++)
{
m_ulongItems[iUIntItem] = 0;
m_ulongItemValidFlags[iUIntItem] = FALSE;
}
ClearKeywords();
ClearPictures();
}
void MetaInfo::ClearItems(UINT32 metaInfoSetFlags)
{
for(int iStrItem = StringMetaItem_Begin_; iStrItem < StringMetaItem_End_; iStrItem++)
{
if(IsItemSupportedByAnySet((eStringMetaItem)iStrItem, metaInfoSetFlags))
{
m_stringItems[iStrItem].Clear();
}
}
for(int iUIntItem = UIntMetaItem_Begin_; iUIntItem < UIntMetaItem_End_; iUIntItem++)
{
if(IsItemSupportedByAnySet((eUIntMetaItem)iUIntItem, metaInfoSetFlags))
@@ -3395,60 +3541,83 @@
return HXR_OK;
}
UINT32 MetaInfo::GetPictureCount() const
{
return (UINT32)m_aPictures.GetSize();
}
ID3Tools::APICFrame* MetaInfo::GetPictureByIndex(UINT32 index) const
{
if(index >= (UINT32)m_aPictures.GetSize())
{
return 0;
}
return (ID3Tools::APICFrame*)m_aPictures.GetAt(index);
}
ID3Tools::APICFrame* MetaInfo::GetPictureByType(UINT8 APICFramePictureType) const
{
for(int i = 0; i < m_aPictures.GetSize(); i++)
{
ID3Tools::APICFrame* pFrame = (ID3Tools::APICFrame*)m_aPictures.GetAt(i);
if(pFrame && (pFrame->GetPictureType() == APICFramePictureType))
{
return pFrame;
}
}
return 0;
}
+CHXString MetaInfo::MakePictureFilename(const ID3Tools::APICFrame& frame, UINT32 index, const CHXString& prefix)
+{
+ CHXString filename = prefix.IsEmpty() ? "picture" : prefix;
+ filename.AppendULONG(index);
+ filename += "_type";
+ filename.AppendULONG(frame.GetPictureType());
+
+ if(frame.GetMimeType() == "image/jpeg")
+ {
+ filename += ".jpg";
+ }
+ else if(frame.GetMimeType() == "image/png")
+ {
+ filename += ".png";
+ }
+ else
+ {
+ filename += ".bin";
+ }
+
+ return filename;
+}
+
HX_RESULT MetaInfo::ClearPictures()
{
ClearAPICFrameArray(m_aPictures);
return HXR_OK;
}
HX_RESULT MetaInfo::AddPicture(ID3Tools::APICFrame* pFrame, UINT32 typeConflictFlags)
{
if(!pFrame)
{
return HXR_INVALID_PARAMETER;
}
ID3Tools::APICFrame* pOldFrame = GetPictureByType(pFrame->GetPictureType());
if(pOldFrame)
{
HXBOOL bResolved = FALSE;
HX_RESULT retVal = HXR_OK;
if(typeConflictFlags & APTCF_FirstChanceOverwrite)
{
retVal = RemovePicture(pOldFrame->GetPictureType());
bResolved = TRUE;
}
if(SUCCEEDED(retVal) && !bResolved && (typeConflictFlags & APTCF_SecondChanceAssignFreeType))
{
UINT8 freePicType = 0;
retVal = FindFreePictureType(freePicType);
if(SUCCEEDED(retVal))
Index: pub/metautil.h
===================================================================
RCS file: /cvsroot/datatype/common/util/pub/metautil.h,v
retrieving revision 1.8
diff -d -H -w -U30 -r1.8 metautil.h
--- pub/metautil.h 6 Jan 2010 17:38:28 -0000 1.8
+++ pub/metautil.h 18 Jan 2010 21:24:10 -0000
@@ -674,116 +674,135 @@
static HXBOOL IsItemSupportedByAllSets(eArrayMetaItem itemName, UINT32 metaInfoSetFlags)
{
return (GetSetsWhichSupportItem(itemName) & metaInfoSetFlags) != metaInfoSetFlags;
}
static UINT32 GetFlavorsWhichSupportItem(eArrayMetaItem itemName);
static HXBOOL IsItemSupportedByAnyFlavor(eArrayMetaItem itemName, UINT32 metaFlavorFlags)
{
return (GetFlavorsWhichSupportItem(itemName) & metaFlavorFlags) != 0;
}
static HXBOOL IsItemSupportedByAllFlavors(eArrayMetaItem itemName, UINT32 metaFlavorFlags)
{
return (GetFlavorsWhichSupportItem(itemName) & metaFlavorFlags) != metaFlavorFlags;
}
static HXBOOL IsKeywordValidForFlavors(const EncodedString& keyword, UINT32 metaFlavorFlags);
static HXBOOL IsAPICFrameValidForFlavors(const ID3Tools::APICFrame& frame, UINT32 metaFlavorFlags);
static HXBOOL IsAPICPictureTypeValidForFlavors(UINT32 pictureType, UINT32 metaFlavorFlags);
static HX_RESULT ScanXMLStringEncoding(const UINT8* pXML, UINT32 uXMLSize, HX_TEXT_ENCODING_TYPE& outEncoding);
static HX_RESULT LoadXMLStringFromFile(const char* szFileName, EncodedString& outXML);
static HX_RESULT SaveXMLStringToFile(const char* szFileName, const EncodedString& sXML);
public:
MetaInfo();
~MetaInfo();
MetaInfo(const MetaInfo& rhs);
MetaInfo& operator=(const MetaInfo& rhs);
- void Dump(UINT32 metaInfoSetFlags = METAINFO_SET_ALL);
+ void Dump(UINT32 metaInfoSetFlags = METAINFO_SET_ALL) const;
+ void DumpToXMLString(CHXString& out,
+ const CHXString& uitsFilename = "", const CHXString& picOutFilenamePrefix = "",
+ UINT32 metaInfoSetFlags = METAINFO_SET_ALL, UINT32 tabLevel = 0, UINT32 tabWidth = 2) const;
void Clear();
void ClearItems(UINT32 metaInfoSetFlags = METAINFO_SET_ALL);
HX_RESULT UpdateItems(const MetaInfo& src, UINT32 metaInfoSetFlags = METAINFO_SET_ALL);
HX_RESULT CopyToValues(IUnknown* pContext, IHXValues* pValues, HXBOOL bBlast, UINT32 metaInfoSetFlags = METAINFO_SET_ALL) const;
HX_RESULT CopyFromValues(IHXValues* pValues, HXBOOL bBlast, UINT32 metaInfoSetFlags = METAINFO_SET_ALL);
// Getters always update <out>.
// String getters return success if <out> is empty.
// UINT getters return success if the value copied to <out> is considered valid.
HX_RESULT GetStringItem(eStringMetaItem itemName, EncodedString& out) const;
HX_RESULT SetStringItem(eStringMetaItem itemName, const EncodedString& val, UINT32 metaFlavorFlags = METADATA_FLAVOR_ALL);
HX_RESULT GetUIntItem(eUIntMetaItem itemName, UINT32& out) const;
HX_RESULT SetUIntItem(eUIntMetaItem itemName, UINT32 val, HXBOOL bValid, UINT32 metaFlavorFlags = METADATA_FLAVOR_ALL);
// 3GPP keywords
UINT32 GetKeywordCount() const;
HX_RESULT GetKeyword(UINT32 index, EncodedString& out) const;
HX_RESULT ClearKeywords();
// Returns FALSE if the byte-length of <val> is greater than 255 (maximum allowed by 3GPP).
// Also, maximum number of keywords that can be written to 3GPP file is 255 (this method
// does not check this to allow easier addition/removal, so this should be checked after
// making changes by calling GetKeywordCount and taking appropriate actions).
HX_RESULT AddKeyword(const EncodedString& val);
HX_RESULT RemoveKeyword(const EncodedString& val);
// APIC frames (attached pictures)
UINT32 GetPictureCount() const;
ID3Tools::APICFrame* GetPictureByIndex(UINT32 index) const;
ID3Tools::APICFrame* GetPictureByType(UINT8 APICFramePictureType) const;
+ static CHXString MakePictureFilename(const ID3Tools::APICFrame& frame, UINT32 index, const CHXString& prefix);
HX_RESULT ClearPictures();
enum eAddPictureTypeConflictFlags
{
APTCF_FirstChanceOverwrite = 0x00000001,
APTCF_SecondChanceAssignFreeType = 0x00000002,
APTCF_ThirdChanceOverwrite = 0x00000004
};
// Returns HXR_INVALID_VERSION if the conflict was not resolved
HX_RESULT AddPicture(ID3Tools::APICFrame* pFrame, UINT32 typeConflictFlags = 0);
HX_RESULT RemovePicture(UINT8 APICFramePictureType);
HX_RESULT FindFreePictureType(UINT8& outPictureType);
HX_RESULT ConsolidatePictureTypes();
private:
HX_RESULT SetGlobalLanguageEncoding(const EncodedString& val);
static HX_RESULT SetStringAsciiMaxLen(EncodedString& dst, const EncodedString& val, UINT32 maxLen);
static HX_RESULT SetStringFixedPointNum(EncodedString& dst, const EncodedString& val);
static void Update(EncodedString& dst, const EncodedString& src);
static void Dump(const char* propName, const EncodedString& val, HXBOOL bFullDump = TRUE);
+
+ static void DumpElementToXMLString(CHXString& out, const CHXString& ws,
+ const EncodedString& src, const CHXString& elementName,
+ const CHXString& attributes = "");
+
+ void DumpStringItemToXMLString(CHXString& out, const CHXString& ws,
+ eStringMetaItem item, const CHXString& elementName,
+ const CHXString& attributes = "") const;
+
+ static void DumpUIntToXMLString(CHXString& out, const CHXString& ws, UINT32 src,
+ const CHXString& elementName, const CHXString& attributes = "");
+
+ void DumpUIntItemToXMLString(CHXString& out, const CHXString& ws, eUIntMetaItem item,
+ const CHXString& elementName, const CHXString& attributes = "") const;
+
void CopyString(eStringMetaItem dstItemName, HXBOOL bBlast, IHXValues* pSrcValues, const char* srcEnginePropName);
void CopyString(IUnknown* pContext, IHXValues* pDstValues, HXBOOL bBlast,
const char* dstEnginePropName, eStringMetaItem srcItemName) const;
static HXBOOL IsInRange(UINT32 val, UINT32 min, UINT32 max)
{
return (val >= min) && (val <= max);
}
static HXBOOL IsInRange16(UINT32 val)
{
return IsInRange(val, 0, 0x0000FFFF);
}
static HXBOOL IsInRange8(UINT32 val)
{
return IsInRange(val, 0, 0x000000FF);
}
static HXBOOL IsInRangeBoolean(UINT32 val)
{
return IsInRange(val, 0, 1);
}
static HX_RESULT SetUInt(UINT32& dstVal, HXBOOL& dstValid, UINT32 srcVal, HXBOOL srcValid,
UINT32 minVal = 0, UINT32 maxVal = 0xFFFFFFFF);
static HX_RESULT SetUInt16(UINT32& dstVal, HXBOOL& dstValid, UINT32 srcVal, HXBOOL srcValid)
{
return SetUInt(dstVal, dstValid, srcVal, srcValid, 0, 0x0000FFFF);
}
static HX_RESULT SetUInt8(UINT32& dstVal, HXBOOL& dstValid, UINT32 srcVal, HXBOOL srcValid)
{
return SetUInt(dstVal, dstValid, srcVal, srcValid, 0, 0x000000FF);
datatype_tools_dtdriver_apps_meta3gp.diff
(application/octet-stream, 62.2 KB)
Index: HXXmlInputParser.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/HXXmlInputParser.cpp,v
retrieving revision 1.2.2.1
diff -d -H -w -U30 -r1.2.2.1 HXXmlInputParser.cpp
--- HXXmlInputParser.cpp 14 Jan 2010 22:59:00 -0000 1.2.2.1
+++ HXXmlInputParser.cpp 18 Jan 2010 21:20:05 -0000
@@ -107,69 +107,68 @@
{
// add the name to the path
m_sCurrentElementPath += "/";
m_sCurrentElementPath += pName;
return HXR_OK;
}
STDMETHODIMP CHXXmlInputParser::HandleEndElement(
const char* pName,
UINT32 ulLineNumber,
UINT32 ulColumnNumber)
{
// remove name from path
CHXString sName(pName);
m_sCurrentElementPath = m_sCurrentElementPath.Left(m_sCurrentElementPath.GetLength() - sName.GetLength() -1);
return HXR_OK;
}
STDMETHODIMP CHXXmlInputParser::HandleCharacterData(
IHXBuffer* pBuffer,
UINT32 ulLineNumber,
UINT32 ulColumnNumber)
{
// With current parser implementation we will assume UTF8
EncodedString strValue((const char*)pBuffer->GetBuffer(), HX_TEXT_ENCODING_TYPE_UTF8);
- if(!strValue.IsEmpty())
+ if(!strValue.IsEmpty() && m_pResults && m_pPathDesc)
{
- // copy value for known paths
- XmlPair* currentValue = m_pResults->GetAt(m_sCurrentElementPath);
- if(currentValue != NULL)
+ if(m_pPathDesc->GetAt(m_sCurrentElementPath))
{
- currentValue->xmlValueUTF8 = strValue;
+ m_pResults->Add(new XmlPair(m_sCurrentElementPath, strValue));
}
}
+
return HXR_OK;
}
STDMETHODIMP CHXXmlInputParser::HandleProcessingInstruction(
const char* pTarget,
IHXValues* pAttributes,
UINT32 ulLineNumber,
UINT32 ulColumnNumber)
{
return HXR_OK;
}
STDMETHODIMP CHXXmlInputParser::HandleUnparsedEntityDecl(
const char* pEntityName,
const char* pSystemID,
const char* pPublicID,
const char* pNotationName,
UINT32 ulLineNumber,
UINT32 ulColumnNumber)
{
return HXR_OK;
}
STDMETHODIMP CHXXmlInputParser::HandleNotationDecl(
const char* pNotationName,
const char* pSystemID,
const char* pPublicID,
@@ -213,49 +212,50 @@
{
HX_RESULT hResult;
IUnknown* pUnk = NULL;
hResult = pClassFactory->CreateInstance(CLSID_IHXXMLParser, (void**)&pUnk);
if(hResult != HXR_OK)
{
return hResult;
}
HX_RELEASE(m_pXMLParser);
hResult = pUnk->QueryInterface(IID_IHXXMLParser, (void**)&m_pXMLParser);
if(hResult != HXR_OK)
{
HX_RELEASE(pUnk);
return hResult;
}
HX_RELEASE(pUnk);
hResult = m_pXMLParser->Init(this, NULL, TRUE);
if(hResult != HXR_OK)
{
return hResult;
}
return HXR_OK;
}
-STDMETHODIMP CHXXmlInputParser::Start(CParsedXmlPairs* pResults)
+STDMETHODIMP CHXXmlInputParser::Start(CParsedXmlPairs* pResults, CXmlPathDescs* pPathDesc)
{
m_pResults = pResults;
+ m_pPathDesc = pPathDesc;
m_ParsingResult = HXR_OK;
return HXR_OK;
}
STDMETHODIMP CHXXmlInputParser::Parse(IHXBuffer* pBuffer, HXBOOL bIsFinal)
{
return m_pXMLParser->Parse(pBuffer, bIsFinal);
}
STDMETHODIMP CHXXmlInputParser::EndParse()
{
return m_ParsingResult;
}
Index: HXXmlInputParser.h
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/HXXmlInputParser.h,v
retrieving revision 1.1.2.2
diff -d -H -w -U30 -r1.1.2.2 HXXmlInputParser.h
--- HXXmlInputParser.h 14 Jan 2010 22:59:00 -0000 1.1.2.2
+++ HXXmlInputParser.h 18 Jan 2010 21:20:06 -0000
@@ -21,109 +21,153 @@
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/****************************************************************************
* Includes
*/
#ifndef _HXXMLINPUTPARSER_H_
#define _HXXMLINPUTPARSER_H_
#include "hxcom.h"
#include "hxstring.h"
#include "hxxml.h"
#include "carray.h"
#include "encstr.h"
-struct XmlPair
+struct XmlPathDesc
{
- XmlPair(const CHXString& path, const EncodedString& valueUTF8)
- : xmlPath(path)
- , xmlValueUTF8(valueUTF8)
+ XmlPathDesc(const CHXString& _path)
+ : path(_path)
+ { }
+ CHXString path;
+};
+
+class CXmlPathDescs
+{
+public:
+ ~CXmlPathDescs()
{
+ for(int i = 0; i < descs.GetSize(); i++)
+ {
+ delete (XmlPathDesc*)descs.GetAt(i);
}
- CHXString xmlPath;
- EncodedString xmlValueUTF8;
+ }
+
+ void Add(XmlPathDesc* d)
+ {
+ if(d)
+ {
+ descs.Add(d);
+ }
+ }
+
+ XmlPathDesc* GetAt(const CHXString& xmlPath)
+ {
+ for(int i = 0; i < descs.GetSize(); i++)
+ {
+ XmlPathDesc *d = (XmlPathDesc*)descs.GetAt(i);
+ if(d && (d->path == xmlPath))
+ {
+ return d;
+ }
+ }
+
+ return NULL;
+ }
+
+private:
+ CHXPtrArray descs;
+};
+
+struct XmlPair
+{
+ XmlPair(const CHXString& _path, const EncodedString& _valueUTF8)
+ : path(_path)
+ , valueUTF8(_valueUTF8)
+ { }
+ CHXString path;
+ EncodedString valueUTF8;
};
class CParsedXmlPairs
{
public:
~CParsedXmlPairs()
{
for(int i = 0; i < xmlPairs.GetSize(); i++)
{
delete (XmlPair*)xmlPairs.GetAt(i);
}
}
void Add(XmlPair* pair)
{
xmlPairs.Add(pair);
}
XmlPair* GetAt(const CHXString& xmlPath)
{
for(int i = 0; i < xmlPairs.GetSize(); i++)
{
XmlPair *pair = (XmlPair*)xmlPairs.GetAt(i);
- if (pair->xmlPath == xmlPath)
+ if(pair->path == xmlPath)
{
return pair;
}
}
return NULL;
}
void Dump()
{
for(int i = 0; i < xmlPairs.GetSize(); i++)
{
XmlPair *pair = (XmlPair*)xmlPairs.GetAt(i);
- printf("%s = [", (const char*)pair->xmlPath);
- EncStrUtils::PrintTextUTF8(pair->xmlValueUTF8.GetData());
+ printf("%s = [", (const char*)pair->path);
+ EncStrUtils::PrintTextUTF8(pair->valueUTF8.GetData());
printf("].\n");
}
}
CHXPtrArray* GetAllPairs()
{
return &xmlPairs;
}
private:
CHXPtrArray xmlPairs;
};
/*
* CHXXmlInputParser class implements XML upgrade manifest parser.
*/
class CHXXmlInputParser :
public IHXXMLParserResponse
{
public:
/*
* Class constructor. Initializes a new instance of the CHXXmlInputParser class.
*/
CHXXmlInputParser();
/**************************************************************************
* IHXContextUser methods
**************************************************************************/
STDMETHOD(QueryInterface) (THIS_
REFIID riid,
@@ -244,61 +288,63 @@
STDMETHOD(HandleUnparsedDoctypeDecl) (THIS_
const char* /*IN*/ pDoctype,
const char* /*IN*/ pSystemID,
const char* /*IN*/ pPublicID,
UINT32 /*IN*/ ulLineNumber,
UINT32 /*IN*/ ulColumnNumber);
/************************************************************************
* Method:
* IHXXMLParser::HandleDefault
* Purpose:
* Called with unhandled entitiy data
* Line/column numbers are for the start of the entity
*
*/
STDMETHOD(HandleDefault) (THIS_
IHXBuffer* /*IN*/ pBuffer,
UINT32 /*IN*/ ulLineNumber,
UINT32 /*IN*/ ulColumnNumber);
/*
* Initializes a parser component.
*/
STDMETHOD(Init) (THIS_
IHXCommonClassFactory* /*IN*/ pClassFactory);
/*
* Starts (resets) the parser.
*/
STDMETHOD(Start) (THIS_
- CParsedXmlPairs* pResults);
+ CParsedXmlPairs* pResults,
+ CXmlPathDescs* pPathDesc);
/*
* Parses one buffer of XML data.
*/
STDMETHOD(Parse) (THIS_
IHXBuffer* pBuffer,
HXBOOL bIsFinal);
/*
* Returns parsed manifest and releases the internal reference.
*/
STDMETHOD(EndParse) (THIS_);
protected:
/*
* Component destructor.
*/
~CHXXmlInputParser();
protected:
- LONG32 m_lRefCount; // Reference count.
- IHXXMLParser* m_pXMLParser; // XML parser.
- HX_RESULT m_ParsingResult; // Result of the parsing operation.
- CHXString m_sCurrentElementPath; // Path of the current XML element.
- CParsedXmlPairs* m_pResults; // Parsed results
+ LONG32 m_lRefCount;
+ IHXXMLParser* m_pXMLParser;
+ HX_RESULT m_ParsingResult;
+ CHXString m_sCurrentElementPath;
+ CParsedXmlPairs* m_pResults;
+ CXmlPathDescs* m_pPathDesc;
};
#endif
Index: main.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/main.cpp,v
retrieving revision 1.7.2.4
diff -d -H -w -U30 -r1.7.2.4 main.cpp
--- main.cpp 17 Jan 2010 17:36:55 -0000 1.7.2.4
+++ main.cpp 18 Jan 2010 21:20:09 -0000
@@ -126,62 +126,63 @@
#define TMAIN main
#define TCHXStringCtor(Val) CHXString(Val)
#define TUTF8EncodedStringCtor(Val) EncodedString((const char*)::UTF8FromCCP(Val), HX_TEXT_ENCODING_TYPE_UTF8)
#endif //USE_WIDE_CHAR_COMMAND_LINE
/****************************************************************************
* Build-time messages
*/
#ifdef _WINDOWS
#ifdef USE_WIDE_CHAR_COMMAND_LINE
# pragma message("Using wide-string command-line arguments")
#else
# pragma message("Using legacy-string command-line arguments")
#endif
#endif //_WINDOWS
/****************************************************************************
* DLLAccessPath Variable
*/
ENABLE_DLLACCESS_PATHS(g_Meta3GPAccessPath);
/****************************************************************************
* Defines
*/
-#define PROGRAM_NAME_STRING "RealNetworks meta-data editor"
-#define PROGRAM_COPYRIGHT_STRING "Copyright (c) RealNetworks 2010"
+#define PROGRAM_VENDOR_STRING "RealNetworks"
+#define PROGRAM_NAME_STRING PROGRAM_VENDOR_STRING" meta-data editor"
+#define PROGRAM_COPYRIGHT_STRING "Copyright (c) "PROGRAM_VENDOR_STRING" 2010"
// input/output control
#ifdef _WINDOWS
#define OPTION_STRING_ASYNCMODE "dev-asyncmode"
#endif //_WINDOWS
#define OPTION_STRING_DEFMETAPROC "dev-defmetaproc"
#define OPTION_STRING_INPUTFILE "if"
#define OPTION_STRING_OUTPUTFILE "of"
#define OPTION_STRING_XMLINPUTFILE "xmlin"
#define OPTION_STRING_XMLOUTPUTFILE "xmlout"
#define OPTION_STRING_CLEARMETADATA "metaclear"
#define OPTION_STRING_METASTYLE "metastyle"
#define OPTION_STRING_UTF16OUTPUT "utf16"
#define OPTION_STRING_ID3V240OUTPUT "id3v240"
#define OPTION_STRING_ID3V230OUTPUT "id3v230"
#define OPTION_STRING_ID3V2NOOUTPUT "id3v2no"
#define OPTION_STRING_OVERWRITEFILE "overwrite"
#define OPTION_STRING_PRINTMETADATA "print"
#define OPTION_STRING_HELP "help"
#define OPTION_STRING_GENERATEHASH "audiohash"
#define OPTION_STRING_LOGFILE "log"
// common metadata
#define OPTION_STRING_TITLE "title"
#define OPTION_STRING_ARTIST "artist"
#define OPTION_STRING_ALBUM "album"
#define OPTION_STRING_GENRE "genre"
#define OPTION_STRING_COMPOSER "composer"
#define OPTION_STRING_COMMENT "comment"
@@ -247,147 +248,195 @@
#define RC_ERROR_MISSING_ENV_VAR 21
#define RC_ERROR_CANNOT_LOAD_DLL 22
#define RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT 23
#define RC_ERROR_CANNOT_OPEN_INPUT_XML_FILE 31
#define RC_ERROR_BAD_INPUT_XML_FILE 32
#define RC_ERROR_INPUT_MEDIA_FILE_NOT_SPECIFIED 33
#define RC_ERROR_CANNOT_OPEN_INPUT_MEDIA_FILE 34
#define RC_ERROR_OUTPUT_MEDIA_FILE_EXISTS 35
#define RC_ERROR_SAME_INPUT_OUTPUT_MEDIA_FILE 36
#define RC_ERROR_CANNOT_OPEN_INPUT_PICTURE_FILE 37
#define RC_ERROR_UNSUPPORTED_INPUT_PICTURE_TYPE 38
#define RC_ERROR_CANNOT_OPEN_INPUT_UITS_FILE 39
#define RC_ERROR_UNSUPPORTED_INPUT_UITS_ENCODING 40
#define RC_ERROR_OUTPUT_PICTURE_FILE_EXISTS 41
#define RC_ERROR_CANNOT_OUTPUT_PICTURE_FILE 42
#define RC_ERROR_OUTPUT_UITS_FILE_EXISTS 43
#define RC_ERROR_CANNOT_OUTPUT_UITS_FILE 44
#define RC_ERROR_OUTPUT_XML_FILE_EXISTS 45
#define RC_ERROR_CANNOT_OUTPUT_XML_FILE 46
#define RC_ERROR_PROCESSING_MEDIA_FILE 100
/****************************************************************************
* Help display utilities
*/
class OptionDesc
{
public:
- OptionDesc(const char* option_ = 0, const char* option_args_ = 0, const char* desc_ = 0,
- int arg_count_ = 0, const char* xpath_ = 0)
+ // xpath_list_ is an array of CHXString pointers.
+ OptionDesc(const char* option_ = 0, const char* option_args_ = 0,
+ const char* desc_ = 0, int arg_count_ = 0,
+ const char* xpath_ = 0, CHXPtrArray* xpath_list_ = 0)
{
option = option_;
option_args = option_args_;
desc = desc_;
arg_count = arg_count_;
- xpath = xpath_;
+
+ if(xpath_list_)
+ {
+ xpaths = xpath_list_;
+ }
+ else
+ {
+ xpaths = new CHXPtrArray;
+ }
+
+ if(xpath_)
+ {
+ xpaths->Add(new CHXString(xpath_));
+ }
+ }
+
+ ~OptionDesc()
+ {
+ for(int i = 0; i < xpaths->GetSize(); i++)
+ {
+ delete (CHXString*)xpaths->GetAt(i);
+ }
+ delete xpaths;
}
UINT32 GetLeftColumnWidth()
{
UINT32 len = 0;
if(option)
{
len += 2 + strlen(option); //leading whitespace and option prefix
if(option_args)
{
len += 1 + strlen(option_args); //whitespace separator and option args
}
}
return len;
}
CHXString BuildLine(UINT32 leftColumnWidth)
{
CHXString out = "";
if(option)
{
out += " -"; //leading whitespace and option prefix
out += option;
if(option_args)
{
out += " "; //whitespace separator
out += option_args;
}
if(desc)
{
INT32 diff = leftColumnWidth - strlen(out);
for(int d = 0; d < diff; d++)
{
out += " ";
}
out += desc;
}
}
return out;
}
const char* GetOptionString() const
{
return option ? option : "";
}
- const char* GetXPath() const
+ int GetNumberOfArguments()
{
- return xpath ? xpath : "";
+ return arg_count;
}
- int GetNumberOfArguments()
+ UINT32 GetNumXPaths() const
{
- return arg_count;
+ return xpaths->GetSize();
+ }
+
+ CHXString GetXPath(int i) const
+ {
+ if(i <= xpaths->GetSize())
+ {
+ return *(CHXString*)xpaths->GetAt(i);
+ }
+ return CHXString();
+ }
+
+ HXBOOL MatchesXPath(const CHXString& xpath) const
+ {
+ for(int i = 0; i < xpaths->GetSize(); i++)
+ {
+ if(GetXPath(i) == xpath)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
}
private:
const char* option;
const char* option_args;
const char* desc;
int arg_count;
- const char* xpath;
+ CHXPtrArray* xpaths;
};
class OptionRegistry
{
public:
~OptionRegistry()
{
for(int i = 0; i < descs.GetSize(); i++)
{
delete (OptionDesc*)descs.GetAt(i);
}
}
void Add(OptionDesc* od)
{
+ if(od)
+ {
descs.Add(od);
}
+ }
int CalcLeftColumnWidth()
{
int leftColumnWidth = 0;
for(int i = 0; i < descs.GetSize(); i++)
{
OptionDesc* od = (OptionDesc*)descs.GetAt(i);
int width = od->GetLeftColumnWidth();
if(width > leftColumnWidth)
{
leftColumnWidth = width;
}
}
return leftColumnWidth;
}
void PrintColumns(int columnSpacing = 1)
{
int leftColumnWidth = CalcLeftColumnWidth() + columnSpacing;
for(int i = 0; i < descs.GetSize(); i++)
{
OptionDesc* od = (OptionDesc*)descs.GetAt(i);
CHXString line = od->BuildLine(leftColumnWidth);
if(!line.IsEmpty())
{
printf("%s\n", (const char*)line);
}
}
@@ -409,77 +458,81 @@
for(int i = 0; i < descs.GetSize(); i++)
{
OptionDesc* od = (OptionDesc*)descs.GetAt(i);
if(arg == od->GetOptionString())
{
return TRUE;
}
}
return FALSE;
}
OptionDesc* GetOptionDesc(CHXString& strArg) const
{
for(int i = 0; i < descs.GetSize(); i++)
{
OptionDesc* od = (OptionDesc*)descs.GetAt(i);
if(strArg == od->GetOptionString())
{
return od;
}
}
return NULL;
}
OptionDesc* GetOptionDescWithPath(CHXString& strArg) const
{
for(int i = 0; i < descs.GetSize(); i++)
{
OptionDesc* od = (OptionDesc*)descs.GetAt(i);
- if(strArg == od->GetXPath())
+ if(od->MatchesXPath(strArg))
{
return od;
}
}
return NULL;
}
- void InitializeXmlPairs(CParsedXmlPairs *xmlPairs)
+ void InitializeXmlPathDescs(CXmlPathDescs& xmlPathDescs)
{
for(int i = 0; i < descs.GetSize(); i++)
{
OptionDesc* desc = (OptionDesc*)descs.GetAt(i);
- CHXString xpath(desc->GetXPath());
+
+ for(int iPath = 0; iPath < desc->GetNumXPaths(); iPath++)
+ {
+ CHXString xpath = desc->GetXPath(iPath);
if(!xpath.IsEmpty())
{
- xmlPairs->Add(new XmlPair(xpath, EncodedString()));
+ xmlPathDescs.Add(new XmlPathDesc(xpath));
+ }
}
}
}
private:
CHXPtrArray descs;
};
void DisplayProgramInfo()
{
const char* pszDbg = "";
#if defined(DEBUG) || defined(_DEBUG)
pszDbg = ".debug";
#endif
printf("\n--- %s ---\n %s\n Version %s%s\n\n",
PROGRAM_NAME_STRING, PROGRAM_COPYRIGHT_STRING, TARVER_STRING_VERSION, pszDbg);
}
void DisplayUsage(const TCHAR* argv0, OptionRegistry& optionReg)
{
CHXString exeName = CHXFileSpecUtils::GetCurrentApplication().GetName();
printf("usage: %s [ -option [value]... ]...\n", (const char*)exeName);
printf("with options:\n");
optionReg.PrintColumns(2);
}
CHXString GetUTCTimeString()
@@ -680,61 +733,63 @@
{
delete (ID3Tools::APICFrame*)a[i];
}
a.RemoveAll();
}
// meta-data input params
HXBOOL ClearMetaData;
HXBOOL ClearKeywords;
HXBOOL ClearPictures;
HXBOOL GenerateHash;
UINT32 InjectedMetaFlavors;
MetaInfo InjectedMetaInfo;
CHXPtrArray AddedKeywords; //EncodedString pointers
CHXPtrArray RemovedKeywords; //EncodedString pointers
CHXPtrArray AddedPictures; //ID3Tools::APICFrame pointers
CHXPtrArray RemovedPictures; //Integers
// meta-data output storage
MetaInfo ExtractedMetaInfo;
MetaInfo OutboundMetaInfo;
#ifdef HELIX_FEATURE_METAEDIT_AUDIO_HASH
unsigned char SHAHash[32];
hash_state HashState;
#endif
};
struct InputOption
{
- InputOption(const CHXString& optionName, const EncodedString& optionValueUTF8, const EncodedString& xmlOptionValueUTF8)
+ InputOption(const CHXString& optionName,
+ const EncodedString& optionValueUTF8 = EncodedString(),
+ const EncodedString& xmlOptionValueUTF8 = EncodedString())
: OptionName(optionName)
, OptionValueUTF8(optionValueUTF8)
, XmlOptionValueUTF8(xmlOptionValueUTF8)
{
}
// XML value has precedence over command-line value
const EncodedString& GetEffectiveOptionValueUTF8() const
{
return XmlOptionValueUTF8.IsEmpty() ? OptionValueUTF8 : XmlOptionValueUTF8;
}
// XML value has precedence over command-line value
CHXString GetEffectiveOptionValueCCP() const
{
const EncodedString& val = GetEffectiveOptionValueUTF8();
return CHXString((const char*)CCPFromUTF8(val.GetData()));
}
CHXString OptionName;
EncodedString OptionValueUTF8;
EncodedString XmlOptionValueUTF8;
};
/****************************************************************************
* Param extractors
*/
enum eCommandLineProcessorPhase
{
CLPP_IndependentOptions = 0,
@@ -1089,173 +1144,203 @@
}
if(bSkipArgOnly)
{
return HXR_OK;
}
if(MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::ArrayMetaItem_Pictures, metaFlavorFlags))
{
EncodedString sVal = option->OptionValueUTF8;
UINT32 uVal = 0;
if(PropTools::ExtractUInt32(uVal, sVal) &&
MetaInfo::IsAPICPictureTypeValidForFlavors(uVal, metaFlavorFlags))
{
aRemovedPictureTypes.AddIfUnique((void*)uVal);
return HXR_OK;
}
ReportInvalidValueForOption(option->OptionName, option->OptionValueUTF8);
return HXR_PARSE_ERROR;
}
ReportUnsupportedMetaStyleOption(option->OptionName);
return HXR_PARSE_ERROR;
}
HX_RESULT ProcessAddPictureOption(int& progRetCode, bool bSkipArgOnly, InputOption* option,
CHXPtrArray& aAddedAPICFrames, UINT32 metaFlavorFlags)
{
- if(option->OptionValueUTF8.IsEmpty())
+ if(option->OptionValueUTF8.IsEmpty() && option->XmlOptionValueUTF8.IsEmpty())
{
return HXR_PARSE_ERROR;
}
if(bSkipArgOnly)
{
return HXR_OK;
}
if(MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::ArrayMetaItem_Pictures, metaFlavorFlags))
{
ID3Tools::APICFrame* pFrame = new ID3Tools::APICFrame;
if(!pFrame)
{
progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
return HXR_OUTOFMEMORY;
}
// process image file
HX_RESULT retVal = HXR_FAILED;
CHXString sFileName = option->GetEffectiveOptionValueCCP();
if(!sFileName.IsEmpty() && CHXFileSpecUtils::FileExists(CHXFileSpecifier(sFileName)))
{
// load image, accept only known MIME types
retVal = pFrame->LoadPictureDataFromImageFile((const char*)sFileName, TRUE);
// check if frame is acceptable
if(SUCCEEDED(retVal) && !MetaInfo::IsAPICFrameValidForFlavors(*pFrame, metaFlavorFlags))
{
+ // xml options override the command line, however, xml options can not be set using the flavor,
+ // so in this case, if the xml option has value which is not valid for flavor, we'll just ignore it.
+ if(option->XmlOptionValueUTF8.IsEmpty())
+ {
retVal = HXR_FAILED;
}
+ }
if(FAILED(retVal))
{
printf("Unsupported picture type in file: %s\n", (const char*)sFileName);
progRetCode = RC_ERROR_UNSUPPORTED_INPUT_PICTURE_TYPE;
}
}
else
{
printf("Failed to open picture file: %s\n", (const char*)sFileName);
progRetCode = RC_ERROR_CANNOT_OPEN_INPUT_PICTURE_FILE;
}
// export frame
if(SUCCEEDED(retVal) && pFrame)
{
if(!aAddedAPICFrames.AddIfUnique(pFrame))
{
retVal = HXR_FAILED;
}
}
if(FAILED(retVal))
{
// cleanup
HX_DELETE(pFrame);
}
return retVal;
}
ReportUnsupportedMetaStyleOption(option->OptionName);
return HXR_PARSE_ERROR;
}
// Only moves argVars position if successful
-HX_RESULT CopyOptionArgumentString(ArgVars& argVars, EncodedString& sOut, HXBOOL bOptional = FALSE)
+HX_RESULT CopyOptionArgumentString(ArgVars& argVars, EncodedString& sOut, HXBOOL bOptional)
{
sOut.Clear();
const TCHAR* pVal = argVars.CurrentArg(1, bOptional, TRUE);
- if(!pVal && !bOptional)
+ if(!pVal)
{
- return HXR_PARSE_ERROR;
+ return bOptional ? HXR_OK : HXR_PARSE_ERROR;
}
sOut = TUTF8EncodedStringCtor(pVal);
argVars.MovePosition(1);
return HXR_OK;
}
class InputOptions
{
public:
InputOptions()
: position(0)
{
}
~InputOptions()
{
Clear();
}
void Clear()
{
for(int i = 0; i < options.GetSize(); i++)
{
delete (InputOption*)options.GetAt(i);
}
options.RemoveAll();
position = 0;
}
void Add(InputOption* inputOpt)
{
+ if(inputOpt)
+ {
options.Add(inputOpt);
}
+ }
+
+ void Remove(const char* strOptionName)
+ {
+ HXBOOL bDone = FALSE;
+ while(!bDone)
+ {
+ bDone = TRUE;
+
+ for(int i = 0; i < options.GetSize(); i++)
+ {
+ InputOption* inOpt = (InputOption*)options.GetAt(i);
+ if(inOpt && (inOpt->OptionName == strOptionName))
+ {
+ options.RemoveAt(i);
+ bDone = FALSE;
+
+ // restart seek loop with new container contents
+ break;
+ }
+ }
+ }
+ }
void ResetPosition(int pos = 0)
{
position = pos;
}
HXBOOL ReachedEndPosition()
{
return (position >= options.GetSize());
}
void MovePosition(int step = 1)
{
position += step;
if(position < 0)
{
position = 0;
}
}
InputOption* GetOption(const CHXString& optionName) const
{
for(int i = 0; i < options.GetSize(); i++)
{
InputOption* option = (InputOption*)options.GetAt(i);
if(option->OptionName == optionName)
{
return option;
}
@@ -1340,76 +1425,77 @@
case 1:
{
// one argument
retVal = CopyOptionArgumentString(argVars, optionArgument, FALSE);
break;
}
default:
// unsupported number of option arguments
retVal = HXR_PARSE_ERROR;
continue;
}
if(FAILED(retVal) && !bStrictMode)
{
retVal = HXR_OK;
argVars.MovePosition(numArgs);
continue;
}
if(SUCCEEDED(retVal))
{
inputOptions.Add(new InputOption(strOption, optionArgument, EncodedString()));
}
}
return retVal;
}
HX_RESULT ParseXMLInputOptions(IHXCommonClassFactory* pCommonClassFactory, CHXXmlInputParser* pInputParser,
- const CHXString& strInputXMLFilename, CParsedXmlPairs* parsedXmlResults)
+ const CHXString& strInputXMLFileName, CParsedXmlPairs& parsedXmlResults,
+ CXmlPathDescs& xmlPathDescs)
{
- if(strInputXMLFilename.IsEmpty())
+ if(strInputXMLFileName.IsEmpty())
{
return HXR_FAIL;
}
- FILE* fp = fopen((const char*)strInputXMLFilename, "r");
+ FILE* fp = fopen((const char*)strInputXMLFileName, "r");
if(fp == NULL)
{
- printf("Unable to open file: %s\n", (const char*)strInputXMLFilename);
+ printf("Unable to open file: %s\n", (const char*)strInputXMLFileName);
return HXR_FAIL;
}
HX_RESULT retVal = HXR_OK;
- retVal = pInputParser->Start(parsedXmlResults);
+ retVal = pInputParser->Start(&parsedXmlResults, &xmlPathDescs);
ULONG32 uParserBufferSize = 64 * 1024;
if(SUCCEEDED(retVal))
{
// create temporary buffer for manifest chunks
IHXBuffer* pBuffer = NULL;
retVal = CreateBufferCCF(pBuffer, pCommonClassFactory);
if(SUCCEEDED(retVal))
{
pBuffer->SetSize(uParserBufferSize);
// read manifest, chunk by chunk
while(true)
{
size_t nItemsRead = fread(pBuffer->GetBuffer(), 1, uParserBufferSize, fp);
if(nItemsRead != 0)
{
if(uParserBufferSize != nItemsRead)
{
pBuffer->SetSize(nItemsRead);
}
// parse chunk
HXBOOL bIsFinal = uParserBufferSize != nItemsRead;
retVal = pInputParser->Parse(pBuffer, bIsFinal);
if(!SUCCEEDED(retVal))
{
break;
}
@@ -1425,60 +1511,107 @@
if(SUCCEEDED(retVal))
{
// retrieve manifest
retVal = pInputParser->EndParse();
}
fclose(fp);
return retVal;
}
HXBOOL NeedOverwriteConfirmation(const char* pFileName, HXBOOL bOverwriteFile)
{
HXBOOL bNeedConfirmation = FALSE;
if(pFileName)
{
if(CHXFileSpecUtils::FileExists(CHXFileSpecifier(pFileName)))
{
if(!bOverwriteFile)
{
bNeedConfirmation = TRUE;
printf("Output file [%s] already exists. Use -%s option to force overwrite.\n",
pFileName, OPTION_STRING_OVERWRITEFILE);
}
}
}
return bNeedConfirmation;
}
+/****************************************************************************
+* XML output utilities
+*/
+HX_RESULT SaveMetadataToXML(const CHXString& filename, const MetaInfo& mi,
+ const CHXString& srcFilename, const CHXString& uitsOutFilename,
+ const CHXString& picOutFilenamePrefix)
+{
+ HX_RESULT retVal = HXR_FAILED;
+
+ if(!filename.IsEmpty())
+ {
+ FILE* fp = fopen((const char*)filename, "w");
+ if(fp)
+ {
+ // write UTF8 BOM
+ const UINT8 BOM_UTF8[3] = { 0xEF, 0xBB, 0xBF };
+ fwrite(BOM_UTF8, 1, 3, fp);
+
+ // begin surrounding elements
+ CHXString exeName = CHXFileSpecUtils::GetCurrentApplication().GetName();
+ exeName = exeName.Left(exeName.Find('.'));
+
+ fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<document type=\"audio meta-data\" date=\"%s\" creator=\"%s\" version=\"%s\" vendor=\"%s\">\n"
+ " <file path=\"%s\">\n",
+ (const char*)GetUTCTimeString(), (const char*)exeName, TARVER_STRING_VERSION, PROGRAM_VENDOR_STRING,
+ (const char*)srcFilename);
+
+ // write metadata elements
+ CHXString sMetadata;
+ mi.DumpToXMLString(sMetadata, uitsOutFilename, picOutFilenamePrefix, METAINFO_SET_ALL, 2, 2);
+ fprintf(fp, "%s", (const char*)sMetadata);
+
+ // end surrounding elements
+ fprintf(fp, " </file>\n"
+ "</document>\n");
+
+ // close file
+ fclose(fp);
+
+ retVal = HXR_OK;
+ }
+ }
+
+ return retVal;
+}
+
/****************************************************************************
* Meta-data processor
*/
class CProcessor : public IHXMetaDataProcessor
{
public:
CProcessor(MetaProcessorVars& vars)
: m_lRefCount(0)
, m_vars(vars)
, m_pContext(0)
{
}
virtual ~CProcessor()
{
HX_RELEASE(m_pContext);
}
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj)
{
if(IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppvObj = (IUnknown*)(IHXMetaDataProcessor*)this;
return HXR_OK;
}
if(IsEqualIID(riid, IID_IHXMetaDataProcessor))
{
AddRef();
*ppvObj = (IHXMetaDataProcessor*)this;
return HXR_OK;
@@ -1643,101 +1776,110 @@
*/
int TMAIN(int argc, TCHAR* argv[])
{
// initialize variables
HX_RESULT retVal = HXR_OK;
int progRetCode = RC_SUCCESS;
UINT32 startTime = 0;
CHXFileSpecifier exeFileSpec;
HXBOOL bUsingLog = FALSE;
DLLAccess* pDLLAccess = 0;
FPHXMEDIAPLATFORMOPEN fpHXMediaPlatformOpen = 0;
FPHXCREATEMEDIAPLATFORM fpHXCreateMediaPlatform = 0;
FPHXMEDIAPLATFORMCLOSE fpHXMediaPlatformClose = 0;
IHXMediaPlatform* pMediaPlatform = 0;
IHXCommonClassFactory* pCommonClassFactory = 0;
CHXXmlInputParser* pInputParser = 0;
IHXMetaDataEditor* pEditor = 0;
CResponse* pResponse = 0;
CProcessor* pProcessor = 0;
IHXValues* pOptions = 0;
char pDllPath[_MAX_PATH] = {0};
char pDllFile[_MAX_PATH] = {0};
const char* pszHelixPluginPath = 0;
CHXString strInputFileName;
CHXString strOutputFileName;
+ CHXString strOutputXMLFileName;
CHXString strPictureFileNamePrefix;
CHXString strUITSDataOutputFileName;
CHXString strMetaStyleName;
HXBOOL bDisplayHelp = FALSE;
HXBOOL bOverwriteFile = FALSE;
HXBOOL bPrintMetaData = FALSE;
HXBOOL bExtractPicturesToFiles = FALSE;
HXBOOL bUTF16Output = FALSE;
UINT32 ulMetaDataID3VersionOutput = METADATAID3VERSION_240;
MetaProcessorVars metaProcessorVars;
// construct option registry
OptionRegistry optionReg;
optionReg.Add(new OptionDesc(OPTION_STRING_LOGFILE, "<filename>", "redirect console output to log file", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_INPUTFILE, "<filename>", "input file", 1, "/albums/album/track/mediaFile/fileName"));
optionReg.Add(new OptionDesc(OPTION_STRING_OUTPUTFILE, "<filename>", "output file", 1, "/albums/album/track/outputFileName"));
optionReg.Add(new OptionDesc(OPTION_STRING_XMLINPUTFILE, "<filename>", "XML file with input parameters", 1));
+ optionReg.Add(new OptionDesc(OPTION_STRING_XMLOUTPUTFILE, "<filename>", "metadata output XML file", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_OVERWRITEFILE, 0, "overwrite output file if it exists", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_CLEARMETADATA, 0, "clear all extracted metadata before injection", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_METASTYLE, "<3GPP | iTunes>", "flavor of injected metadata", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_UTF16OUTPUT, 0, "inject metadata strings in UTF16 format", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_ID3V240OUTPUT, 0, "inject ID3v2 version 2.4.0, default", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_ID3V230OUTPUT, 0, "inject ID3v2 version 2.3.0", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_ID3V2NOOUTPUT, 0, "skip injecting ID3v2 tag", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_PRINTMETADATA, 0, "print updated metadata", 0));
- optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_EXTRACT, "[filename-prefix]", "save extracted pictures", -1));
+ optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_EXTRACT, "[filename prefix]", "save extracted pictures", -1));
optionReg.Add(new OptionDesc(OPTION_STRING_GENERATEHASH, 0, "generate hash", 0));
optionReg.Add(new OptionDesc());
optionReg.Add(new OptionDesc(OPTION_STRING_TITLE, "<string>", "update title", 1, "/albums/album/track/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_ARTIST, "<string>", "update 3GPP performer, iTunes artist", 1, "/albums/album/track/artist/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_ALBUM, "<string>", "update album", 1, "/albums/album/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_GENRE, "<string>", "update genre", 1, "/albums/album/track/style/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_COMPOSER, "<string>", "update 3GPP author, iTunes composer", 1, "/albums/album/track/artist/composer"));
optionReg.Add(new OptionDesc(OPTION_STRING_COMMENT, "<string>", "update 3GPP description, iTunes comment", 1, "/albums/album/pline"));
optionReg.Add(new OptionDesc(OPTION_STRING_COPYRIGHT, "<string>", "update copyright", 1, "/albums/album/cline"));
optionReg.Add(new OptionDesc(OPTION_STRING_TRACKNUMBER, "<integer 0..255>", "update track number", 1, "/albums/album/track/sequence"));
optionReg.Add(new OptionDesc(OPTION_STRING_YEAR, "<integer 0..65536>", "update 3GPP recording year, iTunes release date", 1, "/albums/album/OrigReleaseYear"));
- optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_ADD, "<filename>", "add picture", 1));
+ {
+ // Add picture
+ CHXPtrArray* pPictureAddXPaths = new CHXPtrArray;
+ pPictureAddXPaths->Add(new CHXString("/albums/album/image/fileName"));
+ pPictureAddXPaths->Add(new CHXString("/albums/album/image/fileName2"));
+
+ optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_ADD, "<filename>", "add picture", 1, 0, pPictureAddXPaths));
+ }
optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_REMOVE, "<APIC picture type>", "remove picture", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_CLEAR, 0, "clear all extracted pictures", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_UITS_INSERT, "<filename>", "insert UITS signature from file", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_UITS_EXTRACT, "<filename>", "extract UITS signature into file", 1));
optionReg.Add(new OptionDesc());
optionReg.Add(new OptionDesc(OPTION_STRING_SOFTWARE, "<string>", "update iTunes generator tool", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_ENCODEDBY, "<string>", "update iTunes encoded by", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_GROUPING, "<string>", "update iTunes grouping", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_ALBUMARTIST, "<string>", "update iTunes album artist", 1, "/albums/album/artist/name"));
optionReg.Add(new OptionDesc(OPTION_STRING_LYRICS, "<string>", "update iTunes lyrics", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_SUBTITLE, "<string>", "update iTunes track subtitle", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_BPM, "<integer>", "update iTunes beats per minute", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_PARTOFCOMP, "<0 | 1>", "update iTunes part of compilation", 1, "/albums/album/compilation"));
optionReg.Add(new OptionDesc(OPTION_STRING_EXPLICIT, "<0 | 1>", "update iTunes content rating", 1, "/albums/album/explicit"));
optionReg.Add(new OptionDesc(OPTION_STRING_TRACKSTOTAL, "<integer>", "update iTunes track count", 1, "/albums/album/trackCount"));
optionReg.Add(new OptionDesc(OPTION_STRING_DISKNUMBER, "<integer>", "update iTunes disc number", 1, "/albums/album/track/discNumber"));
optionReg.Add(new OptionDesc(OPTION_STRING_DISKSTOTAL, "<integer>", "update iTunes disc count", 1, "/albums/album/discCount"));
optionReg.Add(new OptionDesc());
optionReg.Add(new OptionDesc(OPTION_STRING_RATING_ENTITY, "<4 character code>", "update 3GPP rating entity", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_RATING_CRITERIA, "<4 character code>", "update 3GPP rating criteria", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_RATING_INFO, "<string>", "update 3GPP rating info", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_CLASSIFICATION_ENTITY, "<4 character code>", "update 3GPP classification entity", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_CLASSIFICATION_TABLE, "<integer 0..65535>", "update 3GPP classification table", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_CLASSIFICATION_INFO, "<string>", "update 3GPP classification info", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_KEYWORD_ADD, "<string>", "add 3GPP keyword", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_KEYWORD_REMOVE, "<string>", "remove 3GPP keyword", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_KEYWORD_CLEAR, 0, "clear all extracted 3GPP keywords", 0));
optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_NAME, "<string>", "update 3GPP location name", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_ASTRONOMICAL_BODY, "<string>", "update 3GPP location astronomical body", 1));
optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_ADDITIONAL_NOTES, "<string>", "update 3GPP location notes", 1));
@@ -1965,104 +2107,128 @@
// initialize xml parser
if(SUCCEEDED(retVal))
{
retVal = HXR_OUTOFMEMORY;
pInputParser = new CHXXmlInputParser();
if(pInputParser)
{
pInputParser->AddRef();
retVal = HXR_OK;
}
}
if(SUCCEEDED(retVal))
{
retVal = pInputParser->Init(pCommonClassFactory);
}
if(FAILED(retVal))
{
printf("Failed to initialize XML parser.\n");
progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
goto cleanup;
}
// parse XML input file
if(SUCCEEDED(retVal))
{
InputOption* pOptionXmlIn = inputOptions.GetOption(CHXString(OPTION_STRING_XMLINPUTFILE));
- CHXString strInputXMLFilename = pOptionXmlIn ? pOptionXmlIn->GetEffectiveOptionValueCCP() : CHXString();
+ CHXString strInputXMLFileName = pOptionXmlIn ? pOptionXmlIn->GetEffectiveOptionValueCCP() : CHXString();
- if(!strInputXMLFilename.IsEmpty() && !CHXFileSpecUtils::FileExists(CHXFileSpecifier(strInputXMLFilename)))
+ if(!strInputXMLFileName.IsEmpty() && !CHXFileSpecUtils::FileExists(CHXFileSpecifier(strInputXMLFileName)))
{
- printf("XML input file [%s] not found.\n", (const char*)strInputXMLFilename);
+ printf("XML input file [%s] not found.\n", (const char*)strInputXMLFileName);
retVal = HXR_FAIL;
progRetCode = RC_ERROR_CANNOT_OPEN_INPUT_XML_FILE;
}
- if(SUCCEEDED(retVal) && !strInputXMLFilename.IsEmpty())
+ if(SUCCEEDED(retVal) && !strInputXMLFileName.IsEmpty())
{
- printf("Processing XML input file [%s].\n", (const char*)strInputXMLFilename);
+ printf("Processing XML input file [%s].\n\n", (const char*)strInputXMLFileName);
CParsedXmlPairs parsedXmlResults;
- optionReg.InitializeXmlPairs(&parsedXmlResults);
- retVal = ParseXMLInputOptions(pCommonClassFactory, pInputParser, strInputXMLFilename, &parsedXmlResults);
+ CXmlPathDescs xmlPathDescs;
+ optionReg.InitializeXmlPathDescs(xmlPathDescs);
+
+ retVal = ParseXMLInputOptions(pCommonClassFactory, pInputParser, strInputXMLFileName,
+ parsedXmlResults, xmlPathDescs);
if(SUCCEEDED(retVal))
{
+ HXBOOL bPictureOptionsUpdated = FALSE;
+
// merge parsed results into inputOptions
CHXPtrArray *xmlPairs = parsedXmlResults.GetAllPairs();
for(int i = 0; i < xmlPairs->GetSize(); i++)
{
XmlPair *pair = (XmlPair*)xmlPairs->GetAt(i);
- OptionDesc* optDesc = optionReg.GetOptionDescWithPath(pair->xmlPath);
+ OptionDesc* optDesc = optionReg.GetOptionDescWithPath(pair->path);
// Add only results of XML file parsing which have non-empty value.
- if((optDesc != NULL) && !pair->xmlValueUTF8.IsEmpty())
+ if(optDesc && !pair->valueUTF8.IsEmpty())
{
CHXString strName = optDesc->GetOptionString();
- InputOption* inOpt = inputOptions.GetOption(strName);
+ HXBOOL bForceAddOption = FALSE;
- if(inOpt == NULL)
+ // XML picture options invalidate command line picture options
+ if(strName == OPTION_STRING_PICTURE_ADD)
{
- inputOptions.Add(new InputOption(strName, EncodedString(), pair->xmlValueUTF8));
+ if(!bPictureOptionsUpdated)
+ {
+ bPictureOptionsUpdated = TRUE;
+
+ inputOptions.Remove(OPTION_STRING_PICTURE_ADD);
+ inputOptions.Remove(OPTION_STRING_PICTURE_REMOVE);
+ inputOptions.Remove(OPTION_STRING_PICTURE_CLEAR);
+
+ // implicit clear
+ inputOptions.Add(new InputOption(OPTION_STRING_PICTURE_CLEAR));
+ }
+ bForceAddOption = TRUE;
+ }
+
+ // update command line options
+ InputOption* inOpt = inputOptions.GetOption(strName);
+ if(!inOpt || bForceAddOption)
+ {
+ inputOptions.Add(new InputOption(strName, EncodedString(), pair->valueUTF8));
}
else
{
- inOpt->XmlOptionValueUTF8 = pair->xmlValueUTF8;
+ inOpt->XmlOptionValueUTF8 = pair->valueUTF8;
}
- printf("-%s taken from location [%s], value=[", (const char*)strName, (const char*)pair->xmlPath);
- EncStrUtils::PrintTextUTF8(pair->xmlValueUTF8.GetData());
+ printf("-%s taken from location [%s], value=[", (const char*)strName, (const char*)pair->path);
+ EncStrUtils::PrintTextUTF8(pair->valueUTF8.GetData());
printf("]\n");
}
}
printf("\n");
}
else
{
printf("Error parsing XML input file.\n");
progRetCode = RC_ERROR_BAD_INPUT_XML_FILE;
}
}
}
// Process final combination of command-line and XML file input.
// The first phase seeks for independent arguments, the second phase seeks for dependent arguments.
eCommandLineProcessorPhase clpp = CLPP_IndependentOptions;
while(SUCCEEDED(retVal) && (clpp != CLPP_Done))
{
for(inputOptions.ResetPosition(0); SUCCEEDED(retVal) && !inputOptions.ReachedEndPosition();
inputOptions.MovePosition(1))
{
InputOption* option = inputOptions.CurrentOption();
CHXString strOption = option->OptionName;
if(strOption == OPTION_STRING_HELP)
{
bDisplayHelp = TRUE;
}
@@ -2083,60 +2249,64 @@
// do nothing, already processed
}
else if(strOption == OPTION_STRING_INPUTFILE)
{
strInputFileName = option->GetEffectiveOptionValueCCP();
}
else if(strOption == OPTION_STRING_OUTPUTFILE)
{
strOutputFileName = option->GetEffectiveOptionValueCCP();
}
else if(strOption == OPTION_STRING_OVERWRITEFILE)
{
bOverwriteFile = TRUE;
}
else if(strOption == OPTION_STRING_CLEARMETADATA)
{
metaProcessorVars.ClearMetaData = TRUE;
}
else if(strOption == OPTION_STRING_PRINTMETADATA)
{
bPrintMetaData = TRUE;
}
else if(strOption == OPTION_STRING_GENERATEHASH)
{
metaProcessorVars.GenerateHash = TRUE;
}
else if(strOption == OPTION_STRING_XMLINPUTFILE)
{
// do nothing, already processed
}
+ else if(strOption == OPTION_STRING_XMLOUTPUTFILE)
+ {
+ strOutputXMLFileName = option->GetEffectiveOptionValueCCP();
+ }
else if(strOption == OPTION_STRING_METASTYLE)
{
strMetaStyleName = option->GetEffectiveOptionValueCCP();
if(clpp == CLPP_IndependentOptions)
{
if(SUCCEEDED(retVal) && !strMetaStyleName.IsEmpty())
{
if(!strMetaStyleName.CompareNoCase("3gpp"))
{
metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_3GPP;
}
else if(!strMetaStyleName.CompareNoCase("itunes"))
{
metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_ITUNES;
}
else
{
retVal = HXR_PARSE_ERROR;
progRetCode = RC_ERROR_BAD_COMMAND_LINE;
ReportInvalidValueForOption(OPTION_STRING_METASTYLE, option->GetEffectiveOptionValueUTF8());
}
}
}
}
else if(strOption == OPTION_STRING_UTF16OUTPUT)
{
bUTF16Output = TRUE;
}
else if(strOption == OPTION_STRING_ID3V240OUTPUT)
@@ -2415,60 +2585,61 @@
}
else if(!sFileExt.CompareNoCase("m4a"))
{
metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_ITUNES;
}
}
}
// next phase
clpp = (eCommandLineProcessorPhase)(int(clpp) + 1);
}
// display usage
if(argc == 1)
{
// auto help display if started without options
bDisplayHelp = TRUE;
}
if(bDisplayHelp)
{
DisplayUsage(argv[0], optionReg);
goto cleanup;
}
// cleanup on command-line errors
if(FAILED(retVal))
{
if(retVal == HXR_PARSE_ERROR)
{
+ printf("Found command line error.\n");
progRetCode = RC_ERROR_BAD_COMMAND_LINE;
}
goto cleanup;
}
// check for semantic errors
if(SUCCEEDED(retVal) && strInputFileName.IsEmpty())
{
printf("Input file not specified.\n");
retVal = HXR_PARSE_ERROR;
progRetCode = RC_ERROR_INPUT_MEDIA_FILE_NOT_SPECIFIED;
}
// input file must exist
if(SUCCEEDED(retVal) && !CHXFileSpecUtils::FileExists(CHXFileSpecifier(strInputFileName)))
{
printf("Input file [%s] not found.\n", (const char*)strInputFileName);
retVal = HXR_FAIL;
progRetCode = RC_ERROR_CANNOT_OPEN_INPUT_MEDIA_FILE;
}
if(SUCCEEDED(retVal) && !strOutputFileName.IsEmpty())
{
// writing to input file is not allowed
if(SUCCEEDED(retVal) && (strInputFileName == strOutputFileName))
{
printf("File [%s] cannot be used for both input and output.\n", (const char*)strOutputFileName);
retVal = HXR_FAIL;
progRetCode = RC_ERROR_SAME_INPUT_OUTPUT_MEDIA_FILE;
}
@@ -2631,155 +2802,170 @@
// drive meta-info through meta-editor by using custom meta-data processor
if(SUCCEEDED(retVal))
{
retVal = pEditor->Drive((const char*)strInputFileName, (const char*)strOutputFileName,
(IHXMetaDataProcessor*)pProcessor,
pOptions, (IHXMetaDataEditorResponse*)pResponse);
if(SUCCEEDED(retVal) && !g_bUseDTDriverSynchronousMode)
{
WaitAsyncDriveEnd();
retVal = pResponse->GetTerminationStatus();
}
}
}
if(FAILED(retVal))
{
printf("Failed to process input file [%s].\n", (const char*)strInputFileName);
progRetCode = RC_ERROR_PROCESSING_MEDIA_FILE;
goto cleanup;
}
#ifdef HELIX_FEATURE_METAEDIT_AUDIO_HASH
if(metaProcessorVars.GenerateHash)
{
printf("--- Generated hash ---\n");
for (int i=0; i<32; i++)
{
printf("%x", metaProcessorVars.SHAHash[i]);
}
- printf("\n");
+ printf("\n\n");
}
#endif
// auto dump meta-data if extracting only
if(strOutputFileName.IsEmpty() && !metaProcessorVars.GenerateHash)
{
bPrintMetaData = TRUE;
}
if(SUCCEEDED(retVal) && bPrintMetaData)
{
// dump extracted
printf("--- Extracted meta-data ---\n");
metaProcessorVars.ExtractedMetaInfo.Dump();
printf("\n");
// dump injected
if(!g_bUseDefaultMetaEditorProcessor && !strOutputFileName.IsEmpty())
{
printf("--- Injected meta-data ---\n");
metaProcessorVars.OutboundMetaInfo.Dump();
printf("\n");
}
}
// extract UITS data to file
+ HXBOOL bErrorSavingUITSData = FALSE;
if(SUCCEEDED(retVal) && !strUITSDataOutputFileName.IsEmpty())
{
EncodedString sUITSData;
if(SUCCEEDED(metaProcessorVars.ExtractedMetaInfo.GetStringItem(MetaInfo::StringMetaItem_UITSData, sUITSData))
&& !sUITSData.IsEmpty())
{
- printf("--- Extracting UITSData to file ---\n");
+ printf("--- Outputting UITSData to file ---\n");
printf("Saving UITSData to [%s].\n", (const char*)strUITSDataOutputFileName);
if(NeedOverwriteConfirmation((const char*)strUITSDataOutputFileName, bOverwriteFile))
{
// report error but continue saving other data
progRetCode = RC_ERROR_OUTPUT_UITS_FILE_EXISTS;
+ bErrorSavingUITSData = TRUE;
}
else if(FAILED(MetaInfo::SaveXMLStringToFile((const char*)strUITSDataOutputFileName, sUITSData)))
{
// report error but continue saving other data
printf("Failed to save UITSData.\n");
progRetCode = RC_ERROR_CANNOT_OUTPUT_UITS_FILE;
+ bErrorSavingUITSData = TRUE;
}
printf("\n");
}
}
// extract pictures to files
+ HXBOOL bErrorSavingPictures = FALSE;
if(SUCCEEDED(retVal) && bExtractPicturesToFiles && metaProcessorVars.ExtractedMetaInfo.GetPictureCount())
{
- printf("--- Extracting pictures to files ---\n");
+ printf("--- Outputting pictures to files ---\n");
for(UINT32 iPic = 0; iPic < metaProcessorVars.ExtractedMetaInfo.GetPictureCount(); iPic++)
{
ID3Tools::APICFrame* pFrame = metaProcessorVars.ExtractedMetaInfo.GetPictureByIndex(iPic);
if(pFrame)
{
- CHXString filename = strPictureFileNamePrefix.IsEmpty() ? "picture" : strPictureFileNamePrefix;
- filename.AppendULONG(iPic);
- filename += "_type";
- filename.AppendULONG(pFrame->GetPictureType());
-
- if(pFrame->GetMimeType() == "image/jpeg")
- {
- filename += ".jpg";
- }
- else if(pFrame->GetMimeType() == "image/png")
- {
- filename += ".png";
- }
- else
- {
- filename += ".bin";
- }
+ CHXString filename = MetaInfo::MakePictureFilename(*pFrame, iPic, strPictureFileNamePrefix);
printf("Saving picture %d to [%s].\n", iPic, (const char*)filename);
if(NeedOverwriteConfirmation((const char*)filename, bOverwriteFile))
{
// report error but continue saving other data
progRetCode = RC_ERROR_OUTPUT_PICTURE_FILE_EXISTS;
+ bErrorSavingPictures = TRUE;
}
- else
- {
- if(FAILED(pFrame->SavePictureDataToImageFile((const char*)filename)))
+ else if(FAILED(pFrame->SavePictureDataToImageFile((const char*)filename)))
{
// report error but continue saving other data
printf("Failed to save picture %d.\n", iPic);
progRetCode = RC_ERROR_CANNOT_OUTPUT_PICTURE_FILE;
+ bErrorSavingPictures = TRUE;
}
}
}
+ printf("\n");
+ }
+
+ // save metadata to output XML
+ if(SUCCEEDED(retVal) && !strOutputXMLFileName.IsEmpty())
+ {
+ // save extracted data in extraction mode but injected data in injection mode
+ HXBOOL bSaveExtracted = strOutputFileName.IsEmpty();
+
+ printf("--- Outputting metadata to XML file ---\n");
+ printf("Saving %s metadata to [%s].\n",
+ bSaveExtracted ? "extracted" : "injected", (const char*)strOutputXMLFileName);
+
+ if(NeedOverwriteConfirmation((const char*)strOutputXMLFileName, bOverwriteFile))
+ {
+ // report error but continue saving other data
+ progRetCode = RC_ERROR_OUTPUT_XML_FILE_EXISTS;
+ }
+ else if(FAILED(SaveMetadataToXML(strOutputXMLFileName,
+ bSaveExtracted ? metaProcessorVars.ExtractedMetaInfo : metaProcessorVars.InjectedMetaInfo,
+ bSaveExtracted ? strInputFileName : strOutputFileName,
+ bErrorSavingUITSData ? "" : strUITSDataOutputFileName,
+ bErrorSavingUITSData ? "" : strPictureFileNamePrefix)))
+ {
+ // report error but continue saving other data
+ printf("Failed to save XML metadata file.\n");
+ progRetCode = RC_ERROR_CANNOT_OUTPUT_XML_FILE;
}
printf("\n");
}
if(SUCCEEDED(retVal))
{
UINT32 endTime = HX_GET_BETTERTICKCOUNT();
printf("Done. Processing time: %f seconds.\n", (endTime - startTime) / 1000.0);
}
// cleanup objects
cleanup:
HX_RELEASE(pEditor);
HX_RELEASE(pInputParser);
HX_RELEASE(pProcessor);
HX_RELEASE(pResponse);
HX_RELEASE(pOptions);
HX_RELEASE(pCommonClassFactory);
if(pMediaPlatform)
{
pMediaPlatform->Close();
}
HX_RELEASE(pMediaPlatform);
if(fpHXMediaPlatformClose)
{
fpHXMediaPlatformClose();
}
HX_DELETE(pDLLAccess);
Index: meta3gp.ver
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/Attic/meta3gp.ver,v
retrieving revision 1.1.2.3
diff -d -H -w -U30 -r1.1.2.3 meta3gp.ver
--- meta3gp.ver 14 Jan 2010 22:51:22 -0000 1.1.2.3
+++ meta3gp.ver 18 Jan 2010 21:20:09 -0000
@@ -1,15 +1,15 @@
/* THIS FILE IS GENERATED BY THE BUILD SYSTEM -- DO NOT EDIT
* Copyright (C) 1997-2002 RealNetworks Corporation. All rights reserved.
*/
#ifdef _MACINTOSH
-#define TARVER_ULONG32_VERSION ((1<<28)|(0<<20)|(4<<12)|4)
-#define TARVER_ULONG64_VERSION ((1<<48)|(0<<32)|(4<<16)|4)
+#define TARVER_ULONG32_VERSION ((1<<28)|(0<<20)|(6<<12)|6)
+#define TARVER_ULONG64_VERSION ((1<<48)|(0<<32)|(6<<16)|6)
#else
-#define TARVER_ULONG32_VERSION (UINT32)((1L<<28L)|(0L<<20L)|(4L<< 12L)|4L)
-#define TARVER_ULONG64_VERSION (UINT64)((1L<<48L)|(0L<<32L)|(4L<< 16L)|4L)
+#define TARVER_ULONG32_VERSION (UINT32)((1L<<28L)|(0L<<20L)|(6L<< 12L)|6L)
+#define TARVER_ULONG64_VERSION (UINT64)((1L<<48L)|(0L<<32L)|(6L<< 16L)|6L)
#endif
-#define TARVER_LIST_VERSION 1,0,4,4
+#define TARVER_LIST_VERSION 1,0,6,6
#define TARVER_MAJOR_VERSION 1
#define TARVER_MINOR_VERSION 0
-#define TARVER_STRING_VERSION "1.0.4.4"
+#define TARVER_STRING_VERSION "1.0.6.6"
#define TARVER_STR_BUILD_NAME ""