Audacity  3.0.3
XMLTagHandler.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  XMLTagHandler.cpp
6 
7  Dominic Mazzoni
8  Vaughan Johnson
9 
10 
11 *//****************************************************************//*******************************************************************/
23 
24 
25 #include "XMLTagHandler.h"
26 
27 #ifdef _WIN32
28  #include <windows.h>
29  #include <wx/msw/winundef.h>
30 #endif
31 
32 #include <wx/defs.h>
33 #include <wx/arrstr.h>
34 #include <wx/filename.h>
35 
36 #include "FileNames.h"
37 
38 // Length check. Is in part about not supplying malicious strings to file functions.
39 bool XMLValueChecker::IsGoodString(const wxString & str)
40 {
41  // Originally based on MAX_PATH, which is way too limiting and just wrong since
42  // the length check is for a plain string and not a filename
43  if (IsGoodLongString(str) && str.length() <= 4096) // Shouldn't be any reason for longer strings, except intentional file corruption.
44  {
45  return true;
46  }
47 
48  return false;
49 }
50 
51 // No length check, as e.g. labels could be very long.
52 bool XMLValueChecker::IsGoodLongString(const wxString & str)
53 {
54  return str.Find('\0', false) == wxNOT_FOUND; // No null characters except terminator.
55 }
56 
57 
58 // "Good" means the name is well-formed and names an existing file or folder.
59 bool XMLValueChecker::IsGoodFileName(const FilePath & strFileName, const FilePath & strDirName /* = "{} */)
60 {
61  // Test strFileName.
62  if (!IsGoodFileString(strFileName) ||
63  (strDirName.length() + 1 + strFileName.length() > PLATFORM_MAX_PATH))
64  return false;
65 
66  // Test the corresponding wxFileName.
67  wxFileName fileName(strDirName, strFileName);
68  return (fileName.IsOk() && fileName.FileExists());
69 }
70 
72 {
73  return (IsGoodString(str) &&
74  !str.empty() &&
75 
76  // FILENAME_MAX is 260 in MSVC, but inconsistent across platforms,
77  // sometimes huge, but we use 260 for all platforms.
78  (str.length() <= 260) &&
79 
80  (str.Find(wxFileName::GetPathSeparator()) == -1)); // No path separator characters.
81 }
82 
83 bool XMLValueChecker::IsGoodSubdirName(const FilePath & strSubdirName, const FilePath & strDirName /* = {} */)
84 {
85  // Test strSubdirName.
86  // Note this prevents path separators, and relative path to parents (strDirName),
87  // so fixes vulnerability #3 in the NGS report for UmixIt,
88  // where an attacker could craft an AUP file with relative pathnames to get to system files, for example.
89  if (!IsGoodFileString(strSubdirName) ||
90  (strSubdirName == wxT(".")) || (strSubdirName == wxT("..")) ||
91  (strDirName.length() + 1 + strSubdirName.length() > PLATFORM_MAX_PATH))
92  return false;
93 
94  // Test the corresponding wxFileName.
95  wxFileName fileName(strDirName, strSubdirName);
96  return (fileName.IsOk() && fileName.DirExists());
97 }
98 
99 bool XMLValueChecker::IsGoodPathName(const FilePath & strPathName)
100 {
101  // Test the corresponding wxFileName.
102  wxFileName fileName(strPathName);
103  return XMLValueChecker::IsGoodFileName(fileName.GetFullName(), fileName.GetPath(wxPATH_GET_VOLUME));
104 }
105 
107 {
108  return (IsGoodString(str) &&
109  !str.empty() &&
110  (str.length() <= PLATFORM_MAX_PATH));
111 }
112 
113 
114 bool XMLValueChecker::IsGoodIntForRange(const wxString & strInt, const wxString & strMAXABS)
115 {
116  if (!IsGoodString(strInt))
117  return false;
118 
119  // Check that the value won't overflow.
120  // Must lie between -Range and +Range-1
121  // We're strict about disallowing spaces and commas, and requiring minus sign to be first
122  // char for negative. No + sign for positive numbers. It's disallowed, not optional.
123 
124  const size_t lenMAXABS = strMAXABS.length();
125  const size_t lenStrInt = strInt.length();
126 
127  if( lenStrInt < 1 )
128  return false;
129  size_t offset = (strInt[0] == '-') ?1:0;
130  if( lenStrInt <= offset )
131  return false;// string too short, no digits in it.
132 
133  if (lenStrInt > (lenMAXABS + offset))
134  return false;
135 
136  unsigned int i;
137  for (i = offset; i < lenStrInt; i++)
138  if (strInt[i] < '0' || strInt[i] > '9' )
139  return false; // not a digit
140 
141  // All chars were digits.
142  if( lenStrInt < (lenMAXABS + offset) )
143  return true; // too few digits to overflow.
144 
145  // Numerical part is same length as strMAXABS
146  for (i = 0; i < lenMAXABS; i++)
147  if (strInt[i+offset] < strMAXABS[i])
148  return true; // number is small enough
149  else if (strInt[i+offset] > strMAXABS[i])
150  return false; // number is too big.
151 
152  // Digits were textually equal to strMAXABS
153  // That's OK if negative, but not OK if positive.
154  return (strInt[0] == '-');
155 }
156 
157 
158 bool XMLValueChecker::IsGoodInt(const wxString & strInt)
159 {
160  // Signed long: -2,147,483,648 to +2,147,483,647, i.e., -2^31 to 2^31-1
161  return IsGoodIntForRange( strInt, "2147483648" );
162 }
163 
164 bool XMLValueChecker::IsGoodInt64(const wxString & strInt)
165 {
166  // Signed 64-bit: -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807, i.e., -2^63 to 2^63-1
167  return IsGoodIntForRange( strInt, "9223372036854775808" );
168 }
169 
170 bool XMLValueChecker::IsValidChannel(const int nValue)
171 {
172  return (nValue >= LeftChannel) && (nValue <= MonoChannel);
173 }
174 
175 #ifdef USE_MIDI
177 {
178  return (nValue >= 0 && nValue < (1 << 16));
179 }
180 #endif
181 
183 {
184  return (nValue == int16Sample) || (nValue == int24Sample) || (nValue == floatSample);
185 }
186 
187 bool XMLTagHandler::ReadXMLTag(const char *tag, const char **attrs)
188 {
189  wxArrayString tmp_attrs;
190 
191  while (*attrs) {
192  const char *s = *attrs++;
193  tmp_attrs.push_back(UTF8CTOWX(s));
194  }
195 
196 // JKC: Previously the next line was:
197 // const char **out_attrs = NEW char (const char *)[tmp_attrs.size()+1];
198 // however MSVC doesn't like the constness in this position, so this is now
199 // added by a cast after creating the array of pointers-to-non-const chars.
200  auto out_attrs = std::make_unique<const wxChar *[]>(tmp_attrs.size() + 1);
201  for (size_t i=0; i<tmp_attrs.size(); i++) {
202  out_attrs[i] = tmp_attrs[i];
203  }
204  out_attrs[tmp_attrs.size()] = 0;
205 
206  bool result = HandleXMLTag(UTF8CTOWX(tag), out_attrs.get());
207 
208  return result;
209 }
210 
211 void XMLTagHandler::ReadXMLEndTag(const char *tag)
212 {
214 }
215 
216 void XMLTagHandler::ReadXMLContent(const char *s, int len)
217 {
218  HandleXMLContent(wxString(s, wxConvUTF8, len));
219 }
220 
222 {
223  return HandleXMLChild(UTF8CTOWX(tag));
224 }
FilePath
wxString FilePath
Definition: Identifier.h:227
XMLValueChecker::IsValidSampleFormat
static bool IsValidSampleFormat(const int nValue)
Definition: XMLTagHandler.cpp:182
XMLValueChecker::IsGoodInt
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
Definition: XMLTagHandler.cpp:158
XMLValueChecker::IsGoodPathName
static bool IsGoodPathName(const FilePath &strPathName)
Definition: XMLTagHandler.cpp:99
int24Sample
@ int24Sample
Definition: Types.h:198
XMLTagHandler::HandleXMLEndTag
virtual void HandleXMLEndTag(const wxChar *WXUNUSED(tag))
Definition: XMLTagHandler.h:97
XMLValueChecker::IsGoodInt64
static bool IsGoodInt64(const wxString &strInt)
Check that the supplied string can be converted to a 64bit integer.
Definition: XMLTagHandler.cpp:164
XMLTagHandler::ReadXMLChild
XMLTagHandler * ReadXMLChild(const char *tag)
Definition: XMLTagHandler.cpp:221
floatSample
@ floatSample
Definition: Types.h:199
XMLValueChecker::IsGoodString
static bool IsGoodString(const wxString &str)
Definition: XMLTagHandler.cpp:39
XMLValueChecker::LeftChannel
@ LeftChannel
Definition: XMLTagHandler.h:68
XMLTagHandler.h
XMLValueChecker::IsValidVisibleChannels
static bool IsValidVisibleChannels(const int nValue)
Definition: XMLTagHandler.cpp:176
XMLTagHandler::HandleXMLContent
virtual void HandleXMLContent(const wxString &WXUNUSED(content))
Definition: XMLTagHandler.h:102
XMLValueChecker::MonoChannel
@ MonoChannel
Definition: XMLTagHandler.h:70
XMLTagHandler::ReadXMLTag
bool ReadXMLTag(const char *tag, const char **attrs)
Definition: XMLTagHandler.cpp:187
UTF8CTOWX
#define UTF8CTOWX(X)
Definition: Internat.h:159
XMLValueChecker::IsGoodFileName
static bool IsGoodFileName(const FilePath &strFileName, const FilePath &strDirName={})
Definition: XMLTagHandler.cpp:59
XMLValueChecker::IsGoodFileString
static bool IsGoodFileString(const FilePath &str)
Definition: XMLTagHandler.cpp:71
XMLTagHandler
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:80
XMLValueChecker::IsValidChannel
static bool IsValidChannel(const int nValue)
Definition: XMLTagHandler.cpp:170
XMLValueChecker::IsGoodSubdirName
static bool IsGoodSubdirName(const FilePath &strSubdirName, const FilePath &strDirName={})
Definition: XMLTagHandler.cpp:83
XMLValueChecker::IsGoodLongString
static bool IsGoodLongString(const wxString &str)
Definition: XMLTagHandler.cpp:52
FileNames.h
int16Sample
@ int16Sample
Definition: Types.h:197
PLATFORM_MAX_PATH
#define PLATFORM_MAX_PATH
Definition: FileNames.h:25
XMLTagHandler::HandleXMLTag
virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs)=0
XMLTagHandler::HandleXMLChild
virtual XMLTagHandler * HandleXMLChild(const wxChar *tag)=0
XMLTagHandler::ReadXMLEndTag
void ReadXMLEndTag(const char *tag)
Definition: XMLTagHandler.cpp:211
XMLValueChecker::IsGoodPathString
static bool IsGoodPathString(const FilePath &str)
Definition: XMLTagHandler.cpp:106
XMLValueChecker::IsGoodIntForRange
static bool IsGoodIntForRange(const wxString &strInt, const wxString &strMAXABS)
Definition: XMLTagHandler.cpp:114
XMLTagHandler::ReadXMLContent
void ReadXMLContent(const char *s, int len)
Definition: XMLTagHandler.cpp:216