diff --git a/Source/MediaInfo/File__Analyze.cpp b/Source/MediaInfo/File__Analyze.cpp index 1e9b81d9f..1db1c0f57 100644 --- a/Source/MediaInfo/File__Analyze.cpp +++ b/Source/MediaInfo/File__Analyze.cpp @@ -44,6 +44,8 @@ using namespace tinyxml2; #define memcpy_Unaligned_Unaligned std::memcpy #define memcpy_Unaligned_Unaligned_Once1024 std::memcpy #endif //MEDIAINFO_SSE2_YES +#define FMT_UNICODE 0 +#include "ThirdParty/fmt/format.h" //--------------------------------------------------------------------------- namespace MediaInfoLib @@ -247,7 +249,7 @@ static_assert(sizeof(Conformance_Type_String) / sizeof(Conformance_Type_String[0 //--------------------------------------------------------------------------- #if MEDIAINFO_CONFORMANCE -string BuildConformanceName(const string& ParserName, const char* Prefix, const char* Suffix) +string File__Analyze::BuildConformanceName(const string& ParserName, const char* Prefix, const char* Suffix) { string Result; if (!Prefix) { @@ -387,6 +389,7 @@ void conformance::Streams_Finish_Conformance() } } string Extra; + bool RemoveOneValueCharacter = false; if (!ConformanceError.FramePoss.empty()) { string Frames, Times, Offsets; @@ -492,8 +495,15 @@ void conformance::Streams_Finish_Conformance() Offsets.pop_back(); } if (Frames_HasContent + Times_HasContent + Offsets_HasContent) { - Extra = ' '; - Extra += '('; + if (ConformanceError.Value.back() == ')') { + RemoveOneValueCharacter = true; + Extra = ','; + Extra += ' '; + } + else { + Extra = ' '; + Extra += '('; + } if (Frames == "conf") { Extra += Frames; } @@ -522,7 +532,11 @@ void conformance::Streams_Finish_Conformance() Extra += ')'; } } - A->Fill(StreamKind_Last, StreamPos_Last, (Conformance_String + ConformanceError.Field).c_str(), ConformanceError.Value + Extra); + auto Value = ConformanceError.Value; + if (RemoveOneValueCharacter) + Value.pop_back(); + Value += Extra; + A->Fill(StreamKind_Last, StreamPos_Last, (Conformance_String + ConformanceError.Field).c_str(), Value); } Conformance_Total.clear(); } @@ -2804,7 +2818,7 @@ void File__Analyze::Header_Fill_Size(int64u Size) Name += ' '; } Name += "GeneralCompliance"; - Fill_Conformance(Name.c_str(), "Element size " + to_string(Size - Element_Offset) + " is more than maximal permitted size " + to_string(Element[Element_Level - 2].Next - (File_Offset + Buffer_Offset + Element_Offset))); + Fill_Conformance(Name.c_str(), "Element size is more than maximal permitted size (actual " + to_string(Size - Element_Offset) + ", expected " + to_string(Element[Element_Level - 2].Next - (File_Offset + Buffer_Offset + Element_Offset)) + ")"); } Element[Element_Level-1].Next=Element[Element_Level-2].Next; @@ -4484,7 +4498,21 @@ void File__Analyze::IsTruncated(int64u ExpectedSize, bool MoreThan, const char* Frame_Count_NotParsedIncluded = (int64u)-1; Fill(Stream_General, 0, "IsTruncated", "Yes", Unlimited, true, true); Fill_SetOptions(Stream_General, 0, "IsTruncated", "N NT"); - Fill_Conformance(BuildConformanceName(ParserName, Prefix, "GeneralCompliance").c_str(), "File size " + std::to_string(File_Size) + " is less than expected size " + (ExpectedSize == (int64u)-1 ? std::string() : ((MoreThan ? "at least " : "") + std::to_string(ExpectedSize)))); + auto Percent = (float)File_Size / ExpectedSize * 100; + string ActualPercent; + static const string Zero("0.000000000"); + if (!MoreThan) { + for (auto i = 0; i <= 9; i++) { + ActualPercent = fmt::format("{:.{}f}", Percent, i); + if ((ActualPercent.front() == '0' && !Zero.rfind(ActualPercent, 0))// Not "0%" + || (ActualPercent.front() != '0' && ActualPercent.size() > 2 && ActualPercent[2] != '.')) { // Not "100%" + continue; + } + ActualPercent = ' ' + ActualPercent + '%'; + break; + } + } + Fill_Conformance(BuildConformanceName(ParserName, Prefix, "GeneralCompliance").c_str(), "File size is less than expected size (actual " + fmt::format("{}", File_Size) + ActualPercent + ", expected " + (ExpectedSize == (int64u)-1 ? std::string() : ((MoreThan ? ">=" : "") + fmt::format("{}", ExpectedSize) + ")"))); Merge_Conformance(); Frame_Count = Frame_Count_Save; Frame_Count_NotParsedIncluded = Frame_Count_NotParsedIncluded_Save; diff --git a/Source/MediaInfo/File__Analyze.h b/Source/MediaInfo/File__Analyze.h index c753c55c7..420f12c5b 100644 --- a/Source/MediaInfo/File__Analyze.h +++ b/Source/MediaInfo/File__Analyze.h @@ -1555,6 +1555,7 @@ public : void Merge_Conformance(bool FromConfig = false); void Streams_Finish_Conformance(); virtual string CreateElementName(); + string BuildConformanceName(const string& ParserName, const char* Prefix, const char* Suffix); void IsTruncated(int64u ExpectedSize = (int64u)-1, bool MoreThan = false, const char* Prefix = nullptr); void RanOutOfData(const char* Prefix = nullptr); void SynchLost(const char* Prefix = nullptr); diff --git a/Source/MediaInfo/File__Analyze_MinimizeSize.h b/Source/MediaInfo/File__Analyze_MinimizeSize.h index 40c30ae2b..61473155a 100644 --- a/Source/MediaInfo/File__Analyze_MinimizeSize.h +++ b/Source/MediaInfo/File__Analyze_MinimizeSize.h @@ -1456,6 +1456,7 @@ public : void Merge_Conformance(bool FromConfig = false); void Streams_Finish_Conformance(); virtual string CreateElementName(); + string BuildConformanceName(const string& ParserName, const char* Prefix, const char* Suffix); void IsTruncated(int64u ExpectedSize = (int64u)-1, bool MoreThan = false, const char* Prefix = nullptr); void RanOutOfData(const char* Prefix = nullptr); void SynchLost(const char* Prefix = nullptr); diff --git a/Source/MediaInfo/File__Analyze_Streams_Finish.cpp b/Source/MediaInfo/File__Analyze_Streams_Finish.cpp index 811e022a0..ccfc8f566 100644 --- a/Source/MediaInfo/File__Analyze_Streams_Finish.cpp +++ b/Source/MediaInfo/File__Analyze_Streams_Finish.cpp @@ -3038,6 +3038,12 @@ void File__Analyze::Streams_Finish_StreamOnly_General(size_t StreamPos) } } + const auto& FileExtension_Invalid = Retrieve(Stream_General, StreamPos, "FileExtension_Invalid"); + if (!FileExtension_Invalid.empty()) { + Fill(Stream_General, StreamPos, "ConformanceWarnings", "Yes", Unlimited, true, true); + Fill(Stream_General, StreamPos, "ConformanceWarnings GeneralCompliance", "File name extension is not expected for this file format (actual " + Retrieve(Stream_General, StreamPos, General_FileExtension).To_UTF8() + ", expected " + FileExtension_Invalid.To_UTF8() + ")", true, true); + } + //Audio_Channels_Total if (Retrieve_Const(Stream_General, StreamPos, General_Audio_Channels_Total).empty()) { diff --git a/Source/MediaInfo/MediaInfo_Inform.cpp b/Source/MediaInfo/MediaInfo_Inform.cpp index 83c6dc0ec..9685716ce 100644 --- a/Source/MediaInfo/MediaInfo_Inform.cpp +++ b/Source/MediaInfo/MediaInfo_Inform.cpp @@ -479,7 +479,7 @@ Ztring MediaInfo_Internal::Inform() XML=true; if (MediaInfoLib::Config.Inform_Get()==__T("MAXML")) XML_0_7_78_MA=true; - if (MediaInfoLib::Config.Inform_Get()==__T("MIXML") || MediaInfoLib::Config.Inform_Get()==__T("XML")) + if (MediaInfoLib::Config.Inform_Get()==__T("MIXML") || MediaInfoLib::Config.Inform_Get()==__T("XML") || MediaInfoLib::Config.Inform_Get().MakeLowerCase() == __T("xmlwithattr")) XML_0_7_78_MI=true; #endif //defined(MEDIAINFO_XML_YES) #if defined(MEDIAINFO_JSON_YES) @@ -774,6 +774,9 @@ Ztring MediaInfo_Internal::Inform (stream_t StreamKind, size_t StreamPos, bool I #if defined(MEDIAINFO_XML_YES) XML=MediaInfoLib::Config.Inform_Get()==__T("OLDXML")?true:false; XML_0_7_78=(MediaInfoLib::Config.Inform_Get()==__T("MAXML") || MediaInfoLib::Config.Inform_Get()==__T("MIXML") || MediaInfoLib::Config.Inform_Get() == __T("XML"))?true:false; + bool XWM_WithAttr=(MediaInfoLib::Config.Inform_Get().MakeLowerCase()==__T("xmlwithattr")); + if (XWM_WithAttr) + XML_0_7_78=true; if (XML_0_7_78) XML=true; #endif //defined(MEDIAINFO_XML_YES) @@ -873,6 +876,7 @@ Ztring MediaInfo_Internal::Inform (stream_t StreamKind, size_t StreamPos, bool I //Subs #if defined(MEDIAINFO_XML_YES) || defined(MEDIAINFO_JSON_YES) + bool IsXmlAttributeConformance=false; if (XML || JSON) { const Ztring& NextName=Get((stream_t)StreamKind, StreamPos, Champ_Pos+1, Info_Name); @@ -898,7 +902,11 @@ Ztring MediaInfo_Internal::Inform (stream_t StreamKind, size_t StreamPos, bool I Fields_Current=&Fields; } else + { Nom_ToErase=LastNested->Name.size()+1; + if (XWM_WithAttr && LastNested->Name.rfind(__T("Conformance"), 0)==0) + IsXmlAttributeConformance=true; + } } if (NextName.size()>Nom.size() && !NextName.rfind(Nom, Nom.size()) && NextName[Nom.size()]==__T(' ')) @@ -1056,15 +1064,86 @@ Ztring MediaInfo_Internal::Inform (stream_t StreamKind, size_t StreamPos, bool I Valeur.erase(SlashPos); } + if (IsXmlAttributeConformance) + { + auto Valeur_Parenthesis_Begin = Valeur.find(__T(" (")); + if (Valeur_Parenthesis_Begin != string::npos) { + auto Valeur_Parenthesis_Begin2 = Valeur_Parenthesis_Begin + 2; + auto Valeur_Parenthesis_End = Valeur.find(')', Valeur_Parenthesis_Begin2); + ZtringListList AttributesList; + if (Valeur_Parenthesis_End != string::npos) { + AttributesList.Separator_Set(0, ", "); + AttributesList.Separator_Set(1, " "); + AttributesList.Write(Valeur.substr(Valeur_Parenthesis_Begin2, Valeur_Parenthesis_End - Valeur_Parenthesis_Begin2)); + Valeur.erase(Valeur_Parenthesis_Begin); + } + for (auto& Item : AttributesList) { + if (Item.size() == 1 && Item[0] == __T("conf")) { + Item[0] = __T("frame"); + Item.push_back(__T("conf")); + } + } + if (AttributesList.empty()) { + AttributesList.resize(1); + } + vector AttributesValues; + AttributesValues.resize(AttributesList.size()); + for (size_t i = 0; i < AttributesValues.size(); i++) { + if (AttributesList[i].size() <= 1) { + continue; + } + AttributesValues[i].Separator_Set(0, "+"); + AttributesValues[i].Write(AttributesList[i][1]); + } + + auto ItemCount = 0; + for (const auto& Item : AttributesValues) { + if (ItemCount < Item.size()) { + ItemCount = Item.size(); + } + } + for (size_t j = 0; j < ItemCount; j++) { + auto Node_Current = new Node(Nom.To_UTF8()); + for (size_t i = 0; i < AttributesValues.size(); i++) { + auto Att = AttributesList[i][0].To_UTF8(); + string Value; + if (j < AttributesValues[i].size()) { + Value = AttributesValues[i][j].To_UTF8(); + } + string Att2; + string Value2; + for (size_t k = 2; k < AttributesList[i].size(); k++) { + const auto Item = AttributesList[i][k]; + if (!Item.empty()) { + if (Item.back() == '%') { + Att2 = Att + "_percent"; + Value2 = Item.To_UTF8(); + } + else { + Value += ' '; + Value += Item.To_UTF8(); + } + } + } + Node_Current->Add_Attribute(Att, Value); + if (!Att2.empty()) { + Node_Current->Add_Attribute(Att2, Value2); + } + } + Node_Current->Value = Valeur.To_UTF8(); + Fields_Current->push_back(Node_Current); + } + } + } + else { Node* Node_Current=NULL; Node_Current=new Node(Nom.To_UTF8()); if (Modified==1 && !MediaInfoLib::Config.SkipBinaryData_Get()) //Base64 - Node_Current->Add_Attribute("dt", "binary.base64"); - - if (Modified==1 && MediaInfoLib::Config.SkipBinaryData_Get()) - Node_Current->Value="(Binary data)"; + Node_Current->Add_Attribute("dt", "binary.base64"); + if (Modified == 1 && MediaInfoLib::Config.SkipBinaryData_Get()) + Node_Current->Value = "(Binary data)"; else - Node_Current->Value=Valeur.To_UTF8(); + Node_Current->Value = Valeur.To_UTF8(); Fields_Current->push_back(Node_Current); if (!Format_Profile_More.empty()) @@ -1085,6 +1164,7 @@ Ztring MediaInfo_Internal::Inform (stream_t StreamKind, size_t StreamPos, bool I Fields_Current->push_back(Node_Current); } } + } } #endif //defined(MEDIAINFO_XML_YES) || defined(MEDIAINFO_JSON_YES)