| File: | usr/include/wx-3.2/wx/buffer.h |
| Warning: | line 206, column 14 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // | |||
| 2 | // This file is part of the aMule Project. | |||
| 3 | // | |||
| 4 | // Copyright (c) 2008-2011 aMule Team ( admin@amule.org / http://www.amule.org ) | |||
| 5 | // | |||
| 6 | // Any parts of this program derived from the xMule, lMule or eMule project, | |||
| 7 | // or contributed by third-party developers are copyrighted by their | |||
| 8 | // respective authors. | |||
| 9 | // | |||
| 10 | // This program is free software; you can redistribute it and/or modify | |||
| 11 | // it under the terms of the GNU General Public License as published by | |||
| 12 | // the Free Software Foundation; either version 2 of the License, or | |||
| 13 | // (at your option) any later version. | |||
| 14 | // | |||
| 15 | // This program is distributed in the hope that it will be useful, | |||
| 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 18 | // GNU General Public License for more details. | |||
| 19 | // | |||
| 20 | // You should have received a copy of the GNU General Public License | |||
| 21 | // along with this program; if not, write to the Free Software | |||
| 22 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |||
| 23 | // | |||
| 24 | ||||
| 25 | #include "Path.h" | |||
| 26 | #include "StringFunctions.h" // Needed for filename2char() | |||
| 27 | ||||
| 28 | #include <wx/file.h> | |||
| 29 | #if defined __WINDOWS__ || defined __IRIX__ | |||
| 30 | # include <wx/ffile.h> | |||
| 31 | #endif | |||
| 32 | #include <wx/utils.h> | |||
| 33 | #include <wx/filename.h> | |||
| 34 | #include <algorithm> // Needed for std::min | |||
| 35 | ||||
| 36 | ||||
| 37 | // Windows has case-insensitive paths, so we use a | |||
| 38 | // case-insensitive cmp for that platform. TODO: | |||
| 39 | // Perhaps it would be better to simply lowercase | |||
| 40 | // m_filesystem in the constructor ... | |||
| 41 | #ifdef __WINDOWS__ | |||
| 42 | #define PATHCMP(a, b)wxStrcmp(a, b) wxStricmp(a, b) | |||
| 43 | #define PATHNCMP(a, b, n)wxStrncmp(a, b, n) wxStrnicmp(a, b, n) | |||
| 44 | #else | |||
| 45 | #define PATHCMP(a, b)wxStrcmp(a, b) wxStrcmp(a, b) | |||
| 46 | #define PATHNCMP(a, b, n)wxStrncmp(a, b, n) wxStrncmp(a, b, n) | |||
| 47 | #endif | |||
| 48 | ||||
| 49 | ||||
| 50 | //////////////////////////////////////////////////////////// | |||
| 51 | // Helper functions | |||
| 52 | ||||
| 53 | ||||
| 54 | /** Creates a deep copy of the string, avoiding its ref. counting. */ | |||
| 55 | inline wxString DeepCopy(const wxString& str) | |||
| 56 | { | |||
| 57 | return wxString(str.c_str(), str.Length()); | |||
| 58 | } | |||
| 59 | ||||
| 60 | ||||
| 61 | static wxString Demangle(const wxCharBuffer& fn, const wxString& filename) | |||
| 62 | { | |||
| 63 | wxString result = wxConvUTF8wxGet_wxConvUTF8().cMB2WC(fn); | |||
| 64 | ||||
| 65 | // FIXME: Is this actually needed for osx/msw? | |||
| 66 | if (!result) { | |||
| 67 | // We only try to further demangle if the current locale is | |||
| 68 | // UTF-8, C or POSIX. This is because in any other case, the | |||
| 69 | // current locale is probably the best choice for printing. | |||
| 70 | static wxFontEncoding enc = wxLocale::GetSystemEncoding(); | |||
| 71 | ||||
| 72 | switch (enc) { | |||
| 73 | // SYSTEM is needed for ANSI encodings such as | |||
| 74 | // "POSIX" and "C", which are only 7bit. | |||
| 75 | case wxFONTENCODING_SYSTEM: | |||
| 76 | case wxFONTENCODING_UTF8: | |||
| 77 | result = wxConvISO8859_1wxGet_wxConvISO8859_1().cMB2WC(fn); | |||
| 78 | break; | |||
| 79 | ||||
| 80 | default: | |||
| 81 | // Nothing to do, the filename is probably Ok. | |||
| 82 | result = DeepCopy(filename); | |||
| 83 | } | |||
| 84 | } | |||
| 85 | ||||
| 86 | return result; | |||
| 87 | } | |||
| 88 | ||||
| 89 | ||||
| 90 | /** Splits a full path into its path and filename component. */ | |||
| 91 | inline void DoSplitPath(const wxString& strPath, wxString* path, wxString* name) | |||
| 92 | { | |||
| 93 | bool hasExt = false; | |||
| 94 | wxString ext, vol; | |||
| 95 | ||||
| 96 | wxString* pVol = (path ? &vol : NULL__null); | |||
| 97 | wxString* pExt = (name ? &ext : NULL__null); | |||
| 98 | ||||
| 99 | wxFileName::SplitPath(strPath, pVol, path, name, pExt, &hasExt); | |||
| 100 | ||||
| 101 | if (hasExt && pExt) { | |||
| 102 | *name += wxT(".")L"." + ext; | |||
| 103 | } | |||
| 104 | ||||
| 105 | if (path && vol.Length()) { | |||
| 106 | *path = vol + wxFileName::GetVolumeSeparator() + *path; | |||
| 107 | } | |||
| 108 | } | |||
| 109 | ||||
| 110 | ||||
| 111 | /** Removes invalid chars from a filename. */ | |||
| 112 | static wxString DoCleanup(const wxString& filename, bool keepSpaces, bool isFAT32) | |||
| 113 | { | |||
| 114 | wxString result; | |||
| 115 | for (size_t i = 0; i < filename.Length(); i++) { | |||
| 116 | const wxChar c = filename[i]; | |||
| 117 | ||||
| 118 | switch (c) { | |||
| 119 | case wxT('/')L'/': | |||
| 120 | continue; | |||
| 121 | ||||
| 122 | case wxT('\"')L'\"': | |||
| 123 | case wxT('*')L'*': | |||
| 124 | case wxT('<')L'<': | |||
| 125 | case wxT('>')L'>': | |||
| 126 | case wxT('?')L'?': | |||
| 127 | case wxT('|')L'|': | |||
| 128 | case wxT('\\')L'\\': | |||
| 129 | case wxT(':')L':': | |||
| 130 | if (isFAT32) { | |||
| 131 | continue; | |||
| 132 | } | |||
| 133 | ||||
| 134 | /* fall through */ | |||
| 135 | default: | |||
| 136 | if ((c == wxT(' ')L' ') && !keepSpaces) { | |||
| 137 | result += wxT("%20")L"%20"; | |||
| 138 | } else if (c >= 32) { | |||
| 139 | // Many illegal for filenames in windows | |||
| 140 | // below the 32th char (which is space). | |||
| 141 | result += filename[i]; | |||
| 142 | } | |||
| 143 | } | |||
| 144 | } | |||
| 145 | ||||
| 146 | return result; | |||
| 147 | } | |||
| 148 | ||||
| 149 | ||||
| 150 | /** Does the actual work of adding a postfix ... */ | |||
| 151 | static wxString DoAddPostfix(const wxString& src, const wxString& postfix) | |||
| 152 | { | |||
| 153 | wxFileName fn(src); | |||
| 154 | ||||
| 155 | fn.SetName(fn.GetName() + postfix); | |||
| 156 | ||||
| 157 | return fn.GetFullPath(); | |||
| 158 | } | |||
| 159 | ||||
| 160 | /** Removes the last extension of a filename. */ | |||
| 161 | static wxString DoRemoveExt(const wxString& path) | |||
| 162 | { | |||
| 163 | // Using wxFilename which handles paths, etc. | |||
| 164 | wxFileName tmp(path); | |||
| 165 | tmp.ClearExt(); | |||
| 166 | ||||
| 167 | return tmp.GetFullPath(); | |||
| 168 | } | |||
| 169 | ||||
| 170 | ||||
| 171 | /** Readies a path for use with wxAccess.. */ | |||
| 172 | static wxString DoCleanPath(const wxString& path) | |||
| 173 | { | |||
| 174 | #ifdef __WINDOWS__ | |||
| 175 | // stat fails on windows if there are trailing path-separators. | |||
| 176 | wxString cleanPath = StripSeparators(path, wxString::trailing); | |||
| 177 | ||||
| 178 | // Root paths must end with a separator (X:\ rather than X:). | |||
| 179 | // See comments in wxDirExists. | |||
| 180 | if ((cleanPath.Length() == 2) && (cleanPath.Last() == wxT(':')L':')) { | |||
| 181 | cleanPath += wxFileName::GetPathSeparator(); | |||
| 182 | } | |||
| 183 | ||||
| 184 | return cleanPath; | |||
| 185 | #else | |||
| 186 | return path; | |||
| 187 | #endif | |||
| 188 | } | |||
| 189 | ||||
| 190 | ||||
| 191 | /** Returns true if the two paths are equal. */ | |||
| 192 | static bool IsSameAs(const wxString& a, const wxString& b) | |||
| 193 | { | |||
| 194 | // Cache the current directory | |||
| 195 | const wxString cwd = wxGetCwd(); | |||
| 196 | ||||
| 197 | // We normalize everything, except env. variables, which | |||
| 198 | // can cause problems when the string is not encodable | |||
| 199 | // using wxConvLibc which wxWidgets uses for the purpose. | |||
| 200 | const int flags = (wxPATH_NORM_ALL | wxPATH_NORM_CASE) & ~wxPATH_NORM_ENV_VARS; | |||
| 201 | ||||
| 202 | // Let wxFileName handle the tricky stuff involved in actually | |||
| 203 | // comparing two paths ... Currently, a path ending with a path- | |||
| 204 | // separator will be unequal to the same path without a path- | |||
| 205 | // separator, which is probably for the best, but can could | |||
| 206 | // lead to some unexpected behavior. | |||
| 207 | wxFileName fn1(a); | |||
| 208 | wxFileName fn2(b); | |||
| 209 | ||||
| 210 | fn1.Normalize(flags, cwd); | |||
| 211 | fn2.Normalize(flags, cwd); | |||
| 212 | ||||
| 213 | return (fn1.GetFullPath() == fn2.GetFullPath()); | |||
| 214 | } | |||
| 215 | ||||
| 216 | ||||
| 217 | //////////////////////////////////////////////////////////// | |||
| 218 | // CPath implementation | |||
| 219 | ||||
| 220 | CPath::CPath() | |||
| 221 | { | |||
| 222 | } | |||
| 223 | ||||
| 224 | ||||
| 225 | CPath::CPath(const wxString& filename) | |||
| 226 | { | |||
| 227 | // Equivalent to the default constructor ... | |||
| 228 | if (!filename) { | |||
| 229 | return; | |||
| 230 | } | |||
| 231 | ||||
| 232 | wxCharBuffer fn = filename2char(filename); | |||
| 233 | if (fn.data()) { | |||
| 234 | // Filename is valid in the current locale. This means that | |||
| 235 | // it either originated from a (wx)system-call, or from a | |||
| 236 | // user with a properly setup system. | |||
| 237 | m_filesystem = DeepCopy(filename); | |||
| 238 | m_printable = Demangle(fn, filename); | |||
| 239 | } else { | |||
| 240 | // It's not a valid filename in the current locale, so we'll | |||
| 241 | // have to do some magic. This ensures that the filename is | |||
| 242 | // saved as UTF8, even if the system is not unicode enabled, | |||
| 243 | // preserving the original filename till the user has fixed | |||
| 244 | // his system ... | |||
| 245 | #ifdef __WINDOWS__ | |||
| 246 | // Magic fails on Windows where we always work with wide char file names. | |||
| 247 | m_filesystem = DeepCopy(filename); | |||
| 248 | m_printable = m_filesystem; | |||
| 249 | #else | |||
| 250 | fn = filename.utf8_str(); | |||
| 251 | m_filesystem = wxConvFile(*wxConvFileName).cMB2WC(fn); | |||
| 252 | ||||
| 253 | // There's no need to try to unmangle the filename here. | |||
| 254 | m_printable = DeepCopy(filename); | |||
| 255 | #endif | |||
| 256 | } | |||
| 257 | ||||
| 258 | wxASSERT(m_filesystem.Length())do { if ( m_filesystem.Length() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Path.cpp", 258, __FUNCTION__, "m_filesystem.Length()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 259 | wxASSERT(m_printable.Length())do { if ( m_printable.Length() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Path.cpp", 259, __FUNCTION__, "m_printable.Length()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 260 | } | |||
| 261 | ||||
| 262 | ||||
| 263 | CPath::CPath(const CPath& other) | |||
| 264 | : m_printable(DeepCopy(other.m_printable)) | |||
| 265 | , m_filesystem(DeepCopy(other.m_filesystem)) | |||
| 266 | {} | |||
| 267 | ||||
| 268 | ||||
| 269 | ||||
| 270 | CPath CPath::FromUniv(const wxString& path) | |||
| 271 | { | |||
| 272 | wxCharBuffer fn = path.mb_str(wxConvISO8859_1wxGet_wxConvISO8859_1()); | |||
| 273 | return CPath(wxConvFile(*wxConvFileName).cMB2WC(fn)); | |||
| 274 | } | |||
| 275 | ||||
| 276 | ||||
| 277 | wxString CPath::ToUniv(const CPath& path) | |||
| 278 | { | |||
| 279 | // The logic behind this is that by saving the filename | |||
| 280 | // as a raw bytestream, we can always recreate the on-disk filename, | |||
| 281 | // as if we had read it using wx functions. | |||
| 282 | wxCharBuffer fn = path.m_filesystem.mb_str(wxConvFile(*wxConvFileName)); | |||
| 283 | return wxConvISO8859_1wxGet_wxConvISO8859_1().cMB2WC(fn); | |||
| 284 | } | |||
| 285 | ||||
| 286 | ||||
| 287 | CPath& CPath::operator=(const CPath& other) | |||
| 288 | { | |||
| 289 | if (this != &other) { | |||
| 290 | m_printable = DeepCopy(other.m_printable); | |||
| 291 | m_filesystem = DeepCopy(other.m_filesystem); | |||
| 292 | } | |||
| 293 | ||||
| 294 | return *this; | |||
| 295 | } | |||
| 296 | ||||
| 297 | ||||
| 298 | bool CPath::operator==(const CPath& other) const | |||
| 299 | { | |||
| 300 | return ::IsSameAs(m_filesystem, other.m_filesystem); | |||
| 301 | } | |||
| 302 | ||||
| 303 | ||||
| 304 | bool CPath::operator!=(const CPath& other) const | |||
| 305 | { | |||
| 306 | return !(*this == other); | |||
| 307 | } | |||
| 308 | ||||
| 309 | ||||
| 310 | bool CPath::operator<(const CPath& other) const | |||
| 311 | { | |||
| 312 | return PATHCMP(m_filesystem.c_str(), other.m_filesystem.c_str())wxStrcmp(m_filesystem.c_str(), other.m_filesystem.c_str()) < 0; | |||
| 313 | } | |||
| 314 | ||||
| 315 | ||||
| 316 | bool CPath::IsOk() const | |||
| 317 | { | |||
| 318 | // Something is very wrong if one of the two is empty. | |||
| 319 | return m_printable.Length() && m_filesystem.Length(); | |||
| 320 | } | |||
| 321 | ||||
| 322 | ||||
| 323 | bool CPath::FileExists() const | |||
| 324 | { | |||
| 325 | return wxFileName::FileExists(m_filesystem); | |||
| 326 | } | |||
| 327 | ||||
| 328 | ||||
| 329 | bool CPath::DirExists() const | |||
| 330 | { | |||
| 331 | return wxFileName::DirExists(DoCleanPath(m_filesystem)); | |||
| 332 | } | |||
| 333 | ||||
| 334 | ||||
| 335 | bool CPath::IsDir(EAccess mode) const | |||
| 336 | { | |||
| 337 | wxString path = DoCleanPath(m_filesystem); | |||
| 338 | if (!wxFileName::DirExists(path)) { | |||
| 339 | return false; | |||
| 340 | } else if ((mode & writable) && !wxIsWritable(path)) { | |||
| 341 | return false; | |||
| 342 | } else if ((mode & readable) && !wxIsReadable(path)) { | |||
| 343 | return false; | |||
| 344 | } | |||
| 345 | ||||
| 346 | return true; | |||
| 347 | } | |||
| 348 | ||||
| 349 | ||||
| 350 | bool CPath::IsFile(EAccess mode) const | |||
| 351 | { | |||
| 352 | if (!wxFileName::FileExists(m_filesystem)) { | |||
| 353 | return false; | |||
| 354 | } else if ((mode & writable) && !wxIsWritable(m_filesystem)) { | |||
| 355 | return false; | |||
| 356 | } else if ((mode & readable) && !wxIsReadable(m_filesystem)) { | |||
| 357 | return false; | |||
| 358 | } | |||
| 359 | ||||
| 360 | return true; | |||
| 361 | } | |||
| 362 | ||||
| 363 | ||||
| 364 | wxString CPath::GetRaw() const | |||
| 365 | { | |||
| 366 | // Copy as c-strings to ensure that the CPath objects can safely | |||
| 367 | // be passed across threads (avoiding wxString ref. counting). | |||
| 368 | return DeepCopy(m_filesystem); | |||
| 369 | } | |||
| 370 | ||||
| 371 | ||||
| 372 | wxString CPath::GetPrintable() const | |||
| 373 | { | |||
| 374 | // Copy as c-strings to ensure that the CPath objects can safely | |||
| 375 | // be passed across threads (avoiding wxString ref. counting). | |||
| 376 | return DeepCopy(m_printable); | |||
| 377 | } | |||
| 378 | ||||
| 379 | ||||
| 380 | wxString CPath::GetExt() const | |||
| 381 | { | |||
| 382 | return wxFileName(m_filesystem).GetExt(); | |||
| 383 | } | |||
| 384 | ||||
| 385 | ||||
| 386 | CPath CPath::GetPath() const | |||
| 387 | { | |||
| 388 | CPath path; | |||
| 389 | ::DoSplitPath(m_printable, &path.m_printable, NULL__null); | |||
| 390 | ::DoSplitPath(m_filesystem, &path.m_filesystem, NULL__null); | |||
| 391 | ||||
| 392 | return path; | |||
| 393 | } | |||
| 394 | ||||
| 395 | ||||
| 396 | CPath CPath::GetFullName() const | |||
| 397 | { | |||
| 398 | CPath path; | |||
| 399 | ::DoSplitPath(m_printable, NULL__null, &path.m_printable); | |||
| 400 | ::DoSplitPath(m_filesystem, NULL__null, &path.m_filesystem); | |||
| 401 | ||||
| 402 | return path; | |||
| 403 | ||||
| 404 | } | |||
| 405 | ||||
| 406 | ||||
| 407 | sint64 CPath::GetFileSize() const | |||
| 408 | { | |||
| 409 | if (FileExists()) { | |||
| 410 | wxFile f(m_filesystem); | |||
| 411 | if (f.IsOpened()) { | |||
| 412 | return f.Length(); | |||
| 413 | } | |||
| 414 | } | |||
| 415 | ||||
| 416 | return wxInvalidOffset; | |||
| 417 | } | |||
| 418 | ||||
| 419 | ||||
| 420 | bool CPath::IsSameDir(const CPath& other) const | |||
| 421 | { | |||
| 422 | wxString a = m_filesystem; | |||
| 423 | wxString b = other.m_filesystem; | |||
| 424 | ||||
| 425 | // This check is needed to avoid trouble in the | |||
| 426 | // case where one path is empty, and the other | |||
| 427 | // points to the root dir. | |||
| 428 | if (a.Length() && b.Length()) { | |||
| 429 | a = StripSeparators(a, wxString::trailing); | |||
| 430 | b = StripSeparators(b, wxString::trailing); | |||
| 431 | } | |||
| 432 | ||||
| 433 | return ::IsSameAs(a, b); | |||
| 434 | } | |||
| 435 | ||||
| 436 | ||||
| 437 | CPath CPath::JoinPaths(const CPath& other) const | |||
| 438 | { | |||
| 439 | if (!IsOk()) { | |||
| 440 | return CPath(other); | |||
| 441 | } else if (!other.IsOk()) { | |||
| 442 | return CPath(*this); | |||
| 443 | } | |||
| 444 | ||||
| 445 | CPath joinedPath; | |||
| 446 | // DeepCopy shouldn't be needed, as JoinPaths results in the creation of a new string. | |||
| 447 | joinedPath.m_printable = ::JoinPaths(m_printable, other.m_printable); | |||
| 448 | joinedPath.m_filesystem = ::JoinPaths(m_filesystem, other.m_filesystem); | |||
| 449 | ||||
| 450 | return joinedPath; | |||
| 451 | } | |||
| 452 | ||||
| 453 | ||||
| 454 | CPath CPath::Cleanup(bool keepSpaces, bool isFAT32) const | |||
| 455 | { | |||
| 456 | CPath result; | |||
| 457 | result.m_printable = ::DoCleanup(m_printable, keepSpaces, isFAT32); | |||
| 458 | result.m_filesystem = ::DoCleanup(m_filesystem, keepSpaces, isFAT32); | |||
| 459 | ||||
| 460 | return result; | |||
| 461 | } | |||
| 462 | ||||
| 463 | ||||
| 464 | CPath CPath::AddPostfix(const wxString& postfix) const | |||
| 465 | { | |||
| 466 | wxASSERT(postfix.IsAscii())do { if ( postfix.IsAscii() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Path.cpp", 466, __FUNCTION__, "postfix.IsAscii()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 467 | ||||
| 468 | CPath result; | |||
| 469 | result.m_printable = ::DoAddPostfix(m_printable, postfix); | |||
| 470 | result.m_filesystem = ::DoAddPostfix(m_filesystem, postfix); | |||
| 471 | ||||
| 472 | return result; | |||
| 473 | } | |||
| 474 | ||||
| 475 | ||||
| 476 | CPath CPath::AppendExt(const wxString& ext) const | |||
| 477 | { | |||
| 478 | wxASSERT(ext.IsAscii())do { if ( ext.IsAscii() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Path.cpp", 478, __FUNCTION__, "ext.IsAscii()", ( const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 479 | ||||
| 480 | // Though technically, and empty extension would simply | |||
| 481 | // be another . at the end of the filename, we ignore them. | |||
| 482 | if (ext.IsEmpty()) { | |||
| 483 | return *this; | |||
| 484 | } | |||
| 485 | ||||
| 486 | CPath result(*this); | |||
| 487 | if (ext[0] == wxT('.')L'.') { | |||
| 488 | result.m_printable << ext; | |||
| 489 | result.m_filesystem << ext; | |||
| 490 | } else { | |||
| 491 | result.m_printable << wxT(".")L"." << ext; | |||
| 492 | result.m_filesystem << wxT(".")L"." << ext; | |||
| 493 | } | |||
| 494 | ||||
| 495 | return result; | |||
| 496 | } | |||
| 497 | ||||
| 498 | ||||
| 499 | CPath CPath::RemoveExt() const | |||
| 500 | { | |||
| 501 | CPath result; | |||
| 502 | result.m_printable = DoRemoveExt(m_printable); | |||
| 503 | result.m_filesystem = DoRemoveExt(m_filesystem); | |||
| 504 | ||||
| 505 | return result; | |||
| 506 | } | |||
| 507 | ||||
| 508 | ||||
| 509 | CPath CPath::RemoveAllExt() const | |||
| 510 | { | |||
| 511 | CPath last, current = RemoveExt(); | |||
| 512 | ||||
| 513 | // Loop until all extensions are removed | |||
| 514 | do { | |||
| 515 | last = current; | |||
| 516 | ||||
| 517 | current = last.RemoveExt(); | |||
| 518 | } while (last != current); | |||
| 519 | ||||
| 520 | return current; | |||
| 521 | } | |||
| 522 | ||||
| 523 | ||||
| 524 | bool CPath::StartsWith(const CPath& other) const | |||
| 525 | { | |||
| 526 | // It doesn't make sense comparing invalid paths, | |||
| 527 | // especially since if 'other' was empty, it would | |||
| 528 | // be considered a prefix of any path. | |||
| 529 | if ((IsOk() && other.IsOk()) == false) { | |||
| 530 | return false; | |||
| 531 | } | |||
| 532 | ||||
| 533 | // Adding an separator to avoid partial matches, such as | |||
| 534 | // "/usr/bi" matching "/usr/bin". TODO: Paths should be | |||
| 535 | // normalized first (in the constructor). | |||
| 536 | const wxString a = StripSeparators(m_filesystem, wxString::trailing) + wxFileName::GetPathSeparator(); | |||
| 537 | const wxString b = StripSeparators(other.m_filesystem, wxString::trailing) + wxFileName::GetPathSeparator(); | |||
| 538 | ||||
| 539 | if (a.Length() < b.Length()) { | |||
| 540 | // Cannot possibly be a prefix. | |||
| 541 | return false; | |||
| 542 | } | |||
| 543 | ||||
| 544 | const size_t checkLen = std::min(a.Length(), b.Length()); | |||
| 545 | return PATHNCMP(a.c_str(), b.c_str(), checkLen)wxStrncmp(a.c_str(), b.c_str(), checkLen) == 0; | |||
| 546 | } | |||
| 547 | ||||
| 548 | ||||
| 549 | bool CPath::CloneFile(const CPath& src, const CPath& dst, bool overwrite) | |||
| 550 | { | |||
| 551 | return ::wxCopyFile(src.m_filesystem, dst.m_filesystem, overwrite); | |||
| 552 | } | |||
| 553 | ||||
| 554 | ||||
| 555 | bool CPath::RemoveFile(const CPath& file) | |||
| 556 | { | |||
| 557 | return ::wxRemoveFile(file.m_filesystem); | |||
| 558 | } | |||
| 559 | ||||
| 560 | ||||
| 561 | bool CPath::RenameFile(const CPath& src, const CPath& dst, bool overwrite) | |||
| 562 | { | |||
| 563 | return ::wxRenameFile(src.m_filesystem, dst.m_filesystem, overwrite); | |||
| 564 | } | |||
| 565 | ||||
| 566 | ||||
| 567 | bool CPath::BackupFile(const CPath& src, const wxString& appendix) | |||
| 568 | { | |||
| 569 | wxASSERT(appendix.IsAscii())do { if ( appendix.IsAscii() ) { } else if ( wxTheAssertHandler && (wxOnAssert("Path.cpp", 569, __FUNCTION__, "appendix.IsAscii()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 570 | ||||
| 571 | CPath dst = CPath(src.m_filesystem + appendix); | |||
| 572 | ||||
| 573 | if (CPath::CloneFile(src, dst, true)) { | |||
| 574 | // Try to ensure that the backup gets physically written | |||
| 575 | #if defined __WINDOWS__ || defined __IRIX__ | |||
| 576 | wxFFile backupFile; | |||
| 577 | #else | |||
| 578 | wxFile backupFile; | |||
| 579 | #endif | |||
| 580 | if (backupFile.Open(dst.m_filesystem)) { | |||
| 581 | backupFile.Flush(); | |||
| 582 | } | |||
| 583 | ||||
| 584 | return true; | |||
| 585 | } | |||
| 586 | ||||
| 587 | return false; | |||
| 588 | } | |||
| 589 | ||||
| 590 | ||||
| 591 | bool CPath::RemoveDir(const CPath& file) | |||
| 592 | { | |||
| 593 | return ::wxRmdir(file.m_filesystem); | |||
| 594 | } | |||
| 595 | ||||
| 596 | ||||
| 597 | bool CPath::MakeDir(const CPath& file) | |||
| 598 | { | |||
| 599 | return ::wxMkdir(file.m_filesystem); | |||
| 600 | } | |||
| 601 | ||||
| 602 | ||||
| 603 | bool CPath::FileExists(const wxString& file) | |||
| 604 | { | |||
| 605 | return CPath(file).FileExists(); | |||
| 606 | } | |||
| 607 | ||||
| 608 | ||||
| 609 | bool CPath::DirExists(const wxString& path) | |||
| 610 | { | |||
| 611 | return CPath(path).DirExists(); | |||
| 612 | } | |||
| 613 | ||||
| 614 | ||||
| 615 | sint64 CPath::GetFileSize(const wxString& file) | |||
| 616 | { | |||
| 617 | return CPath(file).GetFileSize(); | |||
| ||||
| 618 | } | |||
| 619 | ||||
| 620 | ||||
| 621 | time_t CPath::GetModificationTime(const CPath& file) | |||
| 622 | { | |||
| 623 | return ::wxFileModificationTime(file.m_filesystem); | |||
| 624 | } | |||
| 625 | ||||
| 626 | ||||
| 627 | sint64 CPath::GetFreeSpaceAt(const CPath& path) | |||
| 628 | { | |||
| 629 | wxLongLong free; | |||
| 630 | if (::wxGetDiskSpace(path.m_filesystem, NULL__null, &free)) { | |||
| 631 | return free.GetValue(); | |||
| 632 | } | |||
| 633 | ||||
| 634 | return wxInvalidOffset; | |||
| 635 | } | |||
| 636 | ||||
| 637 | ||||
| 638 | wxString CPath::TruncatePath(size_t length, bool isFilePath) const | |||
| 639 | { | |||
| 640 | wxString file = GetPrintable(); | |||
| 641 | ||||
| 642 | // Check if there's anything to do | |||
| 643 | if (file.Length() <= length) { | |||
| 644 | return file; | |||
| 645 | } | |||
| 646 | ||||
| 647 | // If the path is a file name, then prefer to remove from the path, rather than the filename | |||
| 648 | if (isFilePath) { | |||
| 649 | wxString path = wxFileName(file).GetPath(); | |||
| 650 | file = wxFileName(file).GetFullName(); | |||
| 651 | ||||
| 652 | if (path.Length() >= length) { | |||
| 653 | path.Clear(); | |||
| 654 | } else if (file.Length() >= length) { | |||
| 655 | path.Clear(); | |||
| 656 | } else { | |||
| 657 | // Minus 6 for "[...]" + separator | |||
| 658 | int pathlen = (int)(length - file.Length() - 6); | |||
| 659 | ||||
| 660 | if (pathlen > 0) { | |||
| 661 | path = wxT("[...]")L"[...]" + path.Right( pathlen ); | |||
| 662 | } else { | |||
| 663 | path.Clear(); | |||
| 664 | } | |||
| 665 | } | |||
| 666 | ||||
| 667 | file = ::JoinPaths(path, file); | |||
| 668 | } | |||
| 669 | ||||
| 670 | if (file.Length() > length) { | |||
| 671 | if (length > 5) { | |||
| 672 | file = file.Left(length - 5) + wxT("[...]")L"[...]"; | |||
| 673 | } else { | |||
| 674 | file.Clear(); | |||
| 675 | } | |||
| 676 | } | |||
| 677 | ||||
| 678 | return file; | |||
| 679 | } | |||
| 680 | ||||
| 681 | ||||
| 682 | wxString StripSeparators(wxString path, wxString::stripType type) | |||
| 683 | { | |||
| 684 | wxASSERT((type == wxString::leading) || (type == wxString::trailing))do { if ( (type == wxString::leading) || (type == wxString::trailing ) ) { } else if ( wxTheAssertHandler && (wxOnAssert("Path.cpp" , 684, __FUNCTION__, "(type == wxString::leading) || (type == wxString::trailing)" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 685 | const wxString seps = wxFileName::GetPathSeparators(); | |||
| 686 | ||||
| 687 | while (!path.IsEmpty()) { | |||
| 688 | size_t pos = ((type == wxString::leading) ? 0 : path.Length() - 1); | |||
| 689 | ||||
| 690 | if (seps.Contains(path.GetChar(pos))) { | |||
| 691 | path.Remove(pos, 1); | |||
| 692 | } else { | |||
| 693 | break; | |||
| 694 | } | |||
| 695 | } | |||
| 696 | ||||
| 697 | return path; | |||
| 698 | } | |||
| 699 | ||||
| 700 | ||||
| 701 | wxString JoinPaths(const wxString& path, const wxString& file) | |||
| 702 | { | |||
| 703 | if (path.IsEmpty()) { | |||
| 704 | return file; | |||
| 705 | } else if (file.IsEmpty()) { | |||
| 706 | return path; | |||
| 707 | } | |||
| 708 | ||||
| 709 | return StripSeparators(path, wxString::trailing) | |||
| 710 | + wxFileName::GetPathSeparator() | |||
| 711 | + StripSeparators(file, wxString::leading); | |||
| 712 | } |
| 1 | /////////////////////////////////////////////////////////////////////////////// | |||
| 2 | // Name: wx/buffer.h | |||
| 3 | // Purpose: auto buffer classes: buffers which automatically free memory | |||
| 4 | // Author: Vadim Zeitlin | |||
| 5 | // Modified by: | |||
| 6 | // Created: 12.04.99 | |||
| 7 | // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> | |||
| 8 | // Licence: wxWindows licence | |||
| 9 | /////////////////////////////////////////////////////////////////////////////// | |||
| 10 | ||||
| 11 | #ifndef _WX_BUFFER_H | |||
| 12 | #define _WX_BUFFER_H | |||
| 13 | ||||
| 14 | #include "wx/defs.h" | |||
| 15 | #include "wx/wxcrtbase.h" | |||
| 16 | ||||
| 17 | #include <stdlib.h> // malloc() and free() | |||
| 18 | ||||
| 19 | class WXDLLIMPEXP_FWD_BASE wxCStrData; | |||
| 20 | ||||
| 21 | // ---------------------------------------------------------------------------- | |||
| 22 | // Special classes for (wide) character strings: they use malloc/free instead | |||
| 23 | // of new/delete | |||
| 24 | // ---------------------------------------------------------------------------- | |||
| 25 | ||||
| 26 | // helpers used by wxCharTypeBuffer | |||
| 27 | namespace wxPrivate | |||
| 28 | { | |||
| 29 | ||||
| 30 | struct UntypedBufferData | |||
| 31 | { | |||
| 32 | enum Kind | |||
| 33 | { | |||
| 34 | Owned, | |||
| 35 | NonOwned | |||
| 36 | }; | |||
| 37 | ||||
| 38 | UntypedBufferData(void *str, size_t len, Kind kind = Owned) | |||
| 39 | : m_str(str), m_length(len), m_ref(1), m_owned(kind == Owned) {} | |||
| 40 | ||||
| 41 | ~UntypedBufferData() | |||
| 42 | { | |||
| 43 | if ( m_owned ) | |||
| 44 | free(m_str); | |||
| 45 | } | |||
| 46 | ||||
| 47 | void *m_str; | |||
| 48 | size_t m_length; | |||
| 49 | ||||
| 50 | // "short" to have sizeof(Data)=12 on 32bit archs | |||
| 51 | unsigned short m_ref; | |||
| 52 | ||||
| 53 | bool m_owned; | |||
| 54 | }; | |||
| 55 | ||||
| 56 | // NB: this is defined in string.cpp and not the (non-existent) buffer.cpp | |||
| 57 | WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) UntypedBufferData * GetUntypedNullData(); | |||
| 58 | ||||
| 59 | } // namespace wxPrivate | |||
| 60 | ||||
| 61 | ||||
| 62 | // Reference-counted character buffer for storing string data. The buffer | |||
| 63 | // is only valid for as long as the "parent" object that provided the data | |||
| 64 | // is valid; see wxCharTypeBuffer<T> for persistent variant. | |||
| 65 | template <typename T> | |||
| 66 | class wxScopedCharTypeBuffer | |||
| 67 | { | |||
| 68 | public: | |||
| 69 | typedef T CharType; | |||
| 70 | ||||
| 71 | wxScopedCharTypeBuffer() | |||
| 72 | { | |||
| 73 | m_data = GetNullData(); | |||
| 74 | } | |||
| 75 | ||||
| 76 | // Creates "non-owned" buffer, i.e. 'str' is not owned by the buffer | |||
| 77 | // and doesn't get freed by dtor. Used e.g. to point to wxString's internal | |||
| 78 | // storage. | |||
| 79 | static | |||
| 80 | const wxScopedCharTypeBuffer CreateNonOwned(const CharType *str, | |||
| 81 | size_t len = wxNO_LEN((size_t)-1)) | |||
| 82 | { | |||
| 83 | if ( len == wxNO_LEN((size_t)-1) ) | |||
| 84 | len = wxStrlen(str); | |||
| 85 | ||||
| 86 | wxScopedCharTypeBuffer buf; | |||
| 87 | if ( str ) | |||
| 88 | buf.m_data = new Data(const_cast<CharType*>(str), len, Data::NonOwned); | |||
| 89 | return buf; | |||
| 90 | } | |||
| 91 | ||||
| 92 | // Creates "owned" buffer, i.e. takes over ownership of 'str' and frees it | |||
| 93 | // in dtor (if ref.count reaches 0). | |||
| 94 | static | |||
| 95 | const wxScopedCharTypeBuffer CreateOwned(CharType *str, | |||
| 96 | size_t len = wxNO_LEN((size_t)-1) ) | |||
| 97 | { | |||
| 98 | if ( len == wxNO_LEN((size_t)-1) ) | |||
| 99 | len = wxStrlen(str); | |||
| 100 | ||||
| 101 | wxScopedCharTypeBuffer buf; | |||
| 102 | if ( str ) | |||
| 103 | buf.m_data = new Data(str, len); | |||
| 104 | return buf; | |||
| 105 | } | |||
| 106 | ||||
| 107 | wxScopedCharTypeBuffer(const wxScopedCharTypeBuffer& src) | |||
| 108 | { | |||
| 109 | m_data = src.m_data; | |||
| 110 | IncRef(); | |||
| 111 | } | |||
| 112 | ||||
| 113 | wxScopedCharTypeBuffer& operator=(const wxScopedCharTypeBuffer& src) | |||
| 114 | { | |||
| 115 | if ( &src == this ) | |||
| 116 | return *this; | |||
| 117 | ||||
| 118 | DecRef(); | |||
| 119 | m_data = src.m_data; | |||
| 120 | IncRef(); | |||
| 121 | ||||
| 122 | return *this; | |||
| 123 | } | |||
| 124 | ||||
| 125 | ~wxScopedCharTypeBuffer() | |||
| 126 | { | |||
| 127 | DecRef(); | |||
| 128 | } | |||
| 129 | ||||
| 130 | // NB: this method is only const for backward compatibility. It used to | |||
| 131 | // be needed for auto_ptr-like semantics of the copy ctor, but now | |||
| 132 | // that ref-counting is used, it's not really needed. | |||
| 133 | CharType *release() const | |||
| 134 | { | |||
| 135 | if ( m_data == GetNullData() ) | |||
| 136 | return NULL__null; | |||
| 137 | ||||
| 138 | wxASSERT_MSG( m_data->m_owned, wxT("can't release non-owned buffer") )do { if ( m_data->m_owned ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 138 , __FUNCTION__, "m_data->m_owned", L"can't release non-owned buffer" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 139 | wxASSERT_MSG( m_data->m_ref == 1, wxT("can't release shared buffer") )do { if ( m_data->m_ref == 1 ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 139 , __FUNCTION__, "m_data->m_ref == 1", L"can't release shared buffer" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 140 | ||||
| 141 | CharType * const p = m_data->Get(); | |||
| 142 | ||||
| 143 | wxScopedCharTypeBuffer *self = const_cast<wxScopedCharTypeBuffer*>(this); | |||
| 144 | self->m_data->Set(NULL__null, 0); | |||
| 145 | self->DecRef(); | |||
| 146 | ||||
| 147 | return p; | |||
| 148 | } | |||
| 149 | ||||
| 150 | void reset() | |||
| 151 | { | |||
| 152 | DecRef(); | |||
| 153 | } | |||
| 154 | ||||
| 155 | // For some reasong clang-tidy gives a warning about using freed memory | |||
| 156 | // here even when this is not at all the case, seemingly because it doesn't | |||
| 157 | // follow reference counting logic, i.e. it assumes that it's possible to | |||
| 158 | // delete the data even when it's still referenced. | |||
| 159 | // | |||
| 160 | // Suppress the warning as it's extremely annoying to get it for every use | |||
| 161 | // of wxCharBuffer. | |||
| 162 | // | |||
| 163 | // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDelete) | |||
| 164 | CharType *data() { return m_data->Get(); } | |||
| 165 | // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDelete) | |||
| 166 | const CharType *data() const { return m_data->Get(); } | |||
| 167 | operator const CharType *() const { return data(); } | |||
| 168 | CharType operator[](size_t n) const { return data()[n]; } | |||
| 169 | ||||
| 170 | size_t length() const { return m_data->m_length; } | |||
| 171 | ||||
| 172 | protected: | |||
| 173 | // reference-counted data | |||
| 174 | struct Data : public wxPrivate::UntypedBufferData | |||
| 175 | { | |||
| 176 | Data(CharType *str, size_t len, Kind kind = Owned) | |||
| 177 | : wxPrivate::UntypedBufferData(str, len, kind) | |||
| 178 | { | |||
| 179 | } | |||
| 180 | ||||
| 181 | CharType *Get() const { return static_cast<CharType *>(m_str); } | |||
| 182 | void Set(CharType *str, size_t len) | |||
| 183 | { | |||
| 184 | m_str = str; | |||
| 185 | m_length = len; | |||
| 186 | } | |||
| 187 | }; | |||
| 188 | ||||
| 189 | // placeholder for NULL string, to simplify this code | |||
| 190 | static Data *GetNullData() | |||
| 191 | { | |||
| 192 | return static_cast<Data *>(wxPrivate::GetUntypedNullData()); | |||
| 193 | } | |||
| 194 | ||||
| 195 | void IncRef() | |||
| 196 | { | |||
| 197 | if ( m_data == GetNullData() ) // exception, not ref-counted | |||
| 198 | return; | |||
| 199 | m_data->m_ref++; | |||
| 200 | } | |||
| 201 | ||||
| 202 | void DecRef() | |||
| 203 | { | |||
| 204 | if ( m_data == GetNullData() ) // exception, not ref-counted | |||
| 205 | return; | |||
| 206 | if ( --m_data->m_ref == 0 ) | |||
| ||||
| 207 | delete m_data; | |||
| 208 | m_data = GetNullData(); | |||
| 209 | } | |||
| 210 | ||||
| 211 | // sets this object to a be copy of 'other'; if 'src' is non-owned, | |||
| 212 | // a deep copy is made and 'this' will contain new instance of the data | |||
| 213 | void MakeOwnedCopyOf(const wxScopedCharTypeBuffer& src) | |||
| 214 | { | |||
| 215 | this->DecRef(); | |||
| 216 | ||||
| 217 | if ( src.m_data == this->GetNullData() ) | |||
| 218 | { | |||
| 219 | this->m_data = this->GetNullData(); | |||
| 220 | } | |||
| 221 | else if ( src.m_data->m_owned ) | |||
| 222 | { | |||
| 223 | this->m_data = src.m_data; | |||
| 224 | this->IncRef(); | |||
| 225 | } | |||
| 226 | else | |||
| 227 | { | |||
| 228 | // if the scoped buffer had non-owned data, we have to make | |||
| 229 | // a copy here, because src.m_data->m_str is valid only for as long | |||
| 230 | // as 'src' exists | |||
| 231 | this->m_data = new Data | |||
| 232 | ( | |||
| 233 | StrCopy(src.data(), src.length()), | |||
| 234 | src.length() | |||
| 235 | ); | |||
| 236 | } | |||
| 237 | } | |||
| 238 | ||||
| 239 | static CharType *StrCopy(const CharType *src, size_t len) | |||
| 240 | { | |||
| 241 | CharType *dst = (CharType*)malloc(sizeof(CharType) * (len + 1)); | |||
| 242 | if ( dst ) | |||
| 243 | memcpy(dst, src, sizeof(CharType) * (len + 1)); | |||
| 244 | return dst; | |||
| 245 | } | |||
| 246 | ||||
| 247 | protected: | |||
| 248 | Data *m_data; | |||
| 249 | }; | |||
| 250 | ||||
| 251 | typedef wxScopedCharTypeBuffer<char> wxScopedCharBuffer; | |||
| 252 | typedef wxScopedCharTypeBuffer<wchar_t> wxScopedWCharBuffer; | |||
| 253 | ||||
| 254 | ||||
| 255 | // this buffer class always stores data in "owned" (persistent) manner | |||
| 256 | template <typename T> | |||
| 257 | class wxCharTypeBuffer : public wxScopedCharTypeBuffer<T> | |||
| 258 | { | |||
| 259 | protected: | |||
| 260 | typedef typename wxScopedCharTypeBuffer<T>::Data Data; | |||
| 261 | ||||
| 262 | public: | |||
| 263 | typedef T CharType; | |||
| 264 | ||||
| 265 | wxCharTypeBuffer(const CharType *str = NULL__null, size_t len = wxNO_LEN((size_t)-1)) | |||
| 266 | { | |||
| 267 | if ( str ) | |||
| 268 | { | |||
| 269 | if ( len == wxNO_LEN((size_t)-1) ) | |||
| 270 | len = wxStrlen(str); | |||
| 271 | this->m_data = new Data(this->StrCopy(str, len), len); | |||
| 272 | } | |||
| 273 | else | |||
| 274 | { | |||
| 275 | this->m_data = this->GetNullData(); | |||
| 276 | } | |||
| 277 | } | |||
| 278 | ||||
| 279 | wxCharTypeBuffer(size_t len) | |||
| 280 | { | |||
| 281 | CharType* const str = (CharType *)malloc((len + 1)*sizeof(CharType)); | |||
| 282 | if ( str ) | |||
| 283 | { | |||
| 284 | str[len] = (CharType)0; | |||
| 285 | ||||
| 286 | // There is a potential memory leak here if new throws because it | |||
| 287 | // fails to allocate Data, we ought to use new(nothrow) here, but | |||
| 288 | // this might fail to compile under some platforms so until this | |||
| 289 | // can be fully tested, just live with this (rather unlikely, as | |||
| 290 | // Data is a small object) potential leak. | |||
| 291 | this->m_data = new Data(str, len); | |||
| 292 | } | |||
| 293 | else | |||
| 294 | { | |||
| 295 | this->m_data = this->GetNullData(); | |||
| 296 | } | |||
| 297 | } | |||
| 298 | ||||
| 299 | wxCharTypeBuffer(const wxCharTypeBuffer& src) | |||
| 300 | : wxScopedCharTypeBuffer<T>(src) {} | |||
| 301 | ||||
| 302 | wxCharTypeBuffer& operator=(const CharType *str) | |||
| 303 | { | |||
| 304 | this->DecRef(); | |||
| 305 | ||||
| 306 | if ( str ) | |||
| 307 | this->m_data = new Data(wxStrdup(str), wxStrlen(str)); | |||
| 308 | return *this; | |||
| 309 | } | |||
| 310 | ||||
| 311 | wxCharTypeBuffer& operator=(const wxCharTypeBuffer& src) | |||
| 312 | { | |||
| 313 | wxScopedCharTypeBuffer<T>::operator=(src); | |||
| 314 | return *this; | |||
| 315 | } | |||
| 316 | ||||
| 317 | wxCharTypeBuffer(const wxScopedCharTypeBuffer<T>& src) | |||
| 318 | { | |||
| 319 | this->MakeOwnedCopyOf(src); | |||
| 320 | } | |||
| 321 | ||||
| 322 | wxCharTypeBuffer& operator=(const wxScopedCharTypeBuffer<T>& src) | |||
| 323 | { | |||
| 324 | MakeOwnedCopyOf(src); | |||
| 325 | return *this; | |||
| 326 | } | |||
| 327 | ||||
| 328 | bool extend(size_t len) | |||
| 329 | { | |||
| 330 | wxASSERT_MSG( this->m_data->m_owned, "cannot extend non-owned buffer" )do { if ( this->m_data->m_owned ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 330 , __FUNCTION__, "this->m_data->m_owned", "cannot extend non-owned buffer" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 331 | wxASSERT_MSG( this->m_data->m_ref == 1, "can't extend shared buffer" )do { if ( this->m_data->m_ref == 1 ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 331 , __FUNCTION__, "this->m_data->m_ref == 1", "can't extend shared buffer" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 332 | ||||
| 333 | CharType *str = | |||
| 334 | (CharType *)realloc(this->data(), (len + 1) * sizeof(CharType)); | |||
| 335 | if ( !str ) | |||
| 336 | return false; | |||
| 337 | ||||
| 338 | // For consistency with the ctor taking just the length, NUL-terminate | |||
| 339 | // the buffer. | |||
| 340 | str[len] = (CharType)0; | |||
| 341 | ||||
| 342 | if ( this->m_data == this->GetNullData() ) | |||
| 343 | { | |||
| 344 | this->m_data = new Data(str, len); | |||
| 345 | } | |||
| 346 | else | |||
| 347 | { | |||
| 348 | this->m_data->Set(str, len); | |||
| 349 | this->m_data->m_owned = true; | |||
| 350 | } | |||
| 351 | ||||
| 352 | return true; | |||
| 353 | } | |||
| 354 | ||||
| 355 | void shrink(size_t len) | |||
| 356 | { | |||
| 357 | wxASSERT_MSG( this->m_data->m_owned, "cannot shrink non-owned buffer" )do { if ( this->m_data->m_owned ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 357 , __FUNCTION__, "this->m_data->m_owned", "cannot shrink non-owned buffer" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 358 | wxASSERT_MSG( this->m_data->m_ref == 1, "can't shrink shared buffer" )do { if ( this->m_data->m_ref == 1 ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 358 , __FUNCTION__, "this->m_data->m_ref == 1", "can't shrink shared buffer" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 359 | ||||
| 360 | wxASSERT( len <= this->length() )do { if ( len <= this->length() ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 360 , __FUNCTION__, "len <= this->length()", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 361 | ||||
| 362 | this->m_data->m_length = len; | |||
| 363 | this->data()[len] = 0; | |||
| 364 | } | |||
| 365 | }; | |||
| 366 | ||||
| 367 | class wxCharBuffer : public wxCharTypeBuffer<char> | |||
| 368 | { | |||
| 369 | public: | |||
| 370 | typedef wxCharTypeBuffer<char> wxCharTypeBufferBase; | |||
| 371 | typedef wxScopedCharTypeBuffer<char> wxScopedCharTypeBufferBase; | |||
| 372 | ||||
| 373 | wxCharBuffer(const wxCharTypeBufferBase& buf) | |||
| 374 | : wxCharTypeBufferBase(buf) {} | |||
| 375 | wxCharBuffer(const wxScopedCharTypeBufferBase& buf) | |||
| 376 | : wxCharTypeBufferBase(buf) {} | |||
| 377 | ||||
| 378 | wxCharBuffer(const CharType *str = NULL__null) : wxCharTypeBufferBase(str) {} | |||
| 379 | wxCharBuffer(size_t len) : wxCharTypeBufferBase(len) {} | |||
| 380 | ||||
| 381 | wxCharBuffer(const wxCStrData& cstr); | |||
| 382 | }; | |||
| 383 | ||||
| 384 | class wxWCharBuffer : public wxCharTypeBuffer<wchar_t> | |||
| 385 | { | |||
| 386 | public: | |||
| 387 | typedef wxCharTypeBuffer<wchar_t> wxCharTypeBufferBase; | |||
| 388 | typedef wxScopedCharTypeBuffer<wchar_t> wxScopedCharTypeBufferBase; | |||
| 389 | ||||
| 390 | wxWCharBuffer(const wxCharTypeBufferBase& buf) | |||
| 391 | : wxCharTypeBufferBase(buf) {} | |||
| 392 | wxWCharBuffer(const wxScopedCharTypeBufferBase& buf) | |||
| 393 | : wxCharTypeBufferBase(buf) {} | |||
| 394 | ||||
| 395 | wxWCharBuffer(const CharType *str = NULL__null) : wxCharTypeBufferBase(str) {} | |||
| 396 | wxWCharBuffer(size_t len) : wxCharTypeBufferBase(len) {} | |||
| 397 | ||||
| 398 | wxWCharBuffer(const wxCStrData& cstr); | |||
| 399 | }; | |||
| 400 | ||||
| 401 | // wxCharTypeBuffer<T> implicitly convertible to T* | |||
| 402 | template <typename T> | |||
| 403 | class wxWritableCharTypeBuffer : public wxCharTypeBuffer<T> | |||
| 404 | { | |||
| 405 | public: | |||
| 406 | typedef typename wxScopedCharTypeBuffer<T>::CharType CharType; | |||
| 407 | ||||
| 408 | wxWritableCharTypeBuffer(const wxScopedCharTypeBuffer<T>& src) | |||
| 409 | : wxCharTypeBuffer<T>(src) {} | |||
| 410 | // FIXME-UTF8: this won't be needed after converting mb_str()/wc_str() to | |||
| 411 | // always return a buffer | |||
| 412 | // + we should derive this class from wxScopedCharTypeBuffer | |||
| 413 | // then | |||
| 414 | wxWritableCharTypeBuffer(const CharType *str = NULL__null) | |||
| 415 | : wxCharTypeBuffer<T>(str) {} | |||
| 416 | ||||
| 417 | operator CharType*() { return this->data(); } | |||
| 418 | }; | |||
| 419 | ||||
| 420 | typedef wxWritableCharTypeBuffer<char> wxWritableCharBuffer; | |||
| 421 | typedef wxWritableCharTypeBuffer<wchar_t> wxWritableWCharBuffer; | |||
| 422 | ||||
| 423 | ||||
| 424 | #if wxUSE_UNICODE1 | |||
| 425 | #define wxWxCharBufferwxWCharBuffer wxWCharBuffer | |||
| 426 | ||||
| 427 | #define wxMB2WXbufwxWCharBuffer wxWCharBuffer | |||
| 428 | #define wxWX2MBbufwxCharBuffer wxCharBuffer | |||
| 429 | #if wxUSE_UNICODE_WCHAR1 | |||
| 430 | #define wxWC2WXbufwxChar* wxChar* | |||
| 431 | #define wxWX2WCbufwxChar* wxChar* | |||
| 432 | #elif wxUSE_UNICODE_UTF80 | |||
| 433 | #define wxWC2WXbufwxChar* wxWCharBuffer | |||
| 434 | #define wxWX2WCbufwxChar* wxWCharBuffer | |||
| 435 | #endif | |||
| 436 | #else // ANSI | |||
| 437 | #define wxWxCharBufferwxWCharBuffer wxCharBuffer | |||
| 438 | ||||
| 439 | #define wxMB2WXbufwxWCharBuffer wxChar* | |||
| 440 | #define wxWX2MBbufwxCharBuffer wxChar* | |||
| 441 | #define wxWC2WXbufwxChar* wxCharBuffer | |||
| 442 | #define wxWX2WCbufwxChar* wxWCharBuffer | |||
| 443 | #endif // Unicode/ANSI | |||
| 444 | ||||
| 445 | // ---------------------------------------------------------------------------- | |||
| 446 | // A class for holding growable data buffers (not necessarily strings) | |||
| 447 | // ---------------------------------------------------------------------------- | |||
| 448 | ||||
| 449 | // This class manages the actual data buffer pointer and is ref-counted. | |||
| 450 | class wxMemoryBufferData | |||
| 451 | { | |||
| 452 | public: | |||
| 453 | // the initial size and also the size added by ResizeIfNeeded() | |||
| 454 | enum { DefBufSize = 1024 }; | |||
| 455 | ||||
| 456 | friend class wxMemoryBuffer; | |||
| 457 | ||||
| 458 | // everything is private as it can only be used by wxMemoryBuffer | |||
| 459 | private: | |||
| 460 | wxMemoryBufferData(size_t size = wxMemoryBufferData::DefBufSize) | |||
| 461 | : m_data(size ? malloc(size) : NULL__null), m_size(size), m_len(0), m_ref(0) | |||
| 462 | { | |||
| 463 | } | |||
| 464 | ~wxMemoryBufferData() { free(m_data); } | |||
| 465 | ||||
| 466 | ||||
| 467 | void ResizeIfNeeded(size_t newSize) | |||
| 468 | { | |||
| 469 | if (newSize > m_size) | |||
| 470 | { | |||
| 471 | void* const data = realloc(m_data, newSize + wxMemoryBufferData::DefBufSize); | |||
| 472 | if ( !data ) | |||
| 473 | { | |||
| 474 | // It's better to crash immediately dereferencing a null | |||
| 475 | // pointer in the function calling us than overflowing the | |||
| 476 | // buffer which couldn't be made big enough. | |||
| 477 | free(release()); | |||
| 478 | return; | |||
| 479 | } | |||
| 480 | ||||
| 481 | m_data = data; | |||
| 482 | m_size = newSize + wxMemoryBufferData::DefBufSize; | |||
| 483 | } | |||
| 484 | } | |||
| 485 | ||||
| 486 | void IncRef() { m_ref += 1; } | |||
| 487 | void DecRef() | |||
| 488 | { | |||
| 489 | m_ref -= 1; | |||
| 490 | if (m_ref == 0) // are there no more references? | |||
| 491 | delete this; | |||
| 492 | } | |||
| 493 | ||||
| 494 | void *release() | |||
| 495 | { | |||
| 496 | if ( m_data == NULL__null ) | |||
| 497 | return NULL__null; | |||
| 498 | ||||
| 499 | wxASSERT_MSG( m_ref == 1, "can't release shared buffer" )do { if ( m_ref == 1 ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 499, __FUNCTION__ , "m_ref == 1", "can't release shared buffer"), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 500 | ||||
| 501 | void *p = m_data; | |||
| 502 | m_data = NULL__null; | |||
| 503 | m_len = | |||
| 504 | m_size = 0; | |||
| 505 | ||||
| 506 | return p; | |||
| 507 | } | |||
| 508 | ||||
| 509 | ||||
| 510 | // the buffer containing the data | |||
| 511 | void *m_data; | |||
| 512 | ||||
| 513 | // the size of the buffer | |||
| 514 | size_t m_size; | |||
| 515 | ||||
| 516 | // the amount of data currently in the buffer | |||
| 517 | size_t m_len; | |||
| 518 | ||||
| 519 | // the reference count | |||
| 520 | size_t m_ref; | |||
| 521 | ||||
| 522 | wxDECLARE_NO_COPY_CLASS(wxMemoryBufferData)private: wxMemoryBufferData(const wxMemoryBufferData&) = delete ; wxMemoryBufferData& operator=(const wxMemoryBufferData& ) = delete; | |||
| 523 | }; | |||
| 524 | ||||
| 525 | ||||
| 526 | class wxMemoryBuffer | |||
| 527 | { | |||
| 528 | public: | |||
| 529 | // ctor and dtor | |||
| 530 | wxMemoryBuffer(size_t size = wxMemoryBufferData::DefBufSize) | |||
| 531 | { | |||
| 532 | m_bufdata = new wxMemoryBufferData(size); | |||
| 533 | m_bufdata->IncRef(); | |||
| 534 | } | |||
| 535 | ||||
| 536 | ~wxMemoryBuffer() { m_bufdata->DecRef(); } | |||
| 537 | ||||
| 538 | ||||
| 539 | // copy and assignment | |||
| 540 | wxMemoryBuffer(const wxMemoryBuffer& src) | |||
| 541 | : m_bufdata(src.m_bufdata) | |||
| 542 | { | |||
| 543 | m_bufdata->IncRef(); | |||
| 544 | } | |||
| 545 | ||||
| 546 | wxMemoryBuffer& operator=(const wxMemoryBuffer& src) | |||
| 547 | { | |||
| 548 | if (&src != this) | |||
| 549 | { | |||
| 550 | m_bufdata->DecRef(); | |||
| 551 | m_bufdata = src.m_bufdata; | |||
| 552 | m_bufdata->IncRef(); | |||
| 553 | } | |||
| 554 | return *this; | |||
| 555 | } | |||
| 556 | ||||
| 557 | ||||
| 558 | // Accessors | |||
| 559 | void *GetData() const { return m_bufdata->m_data; } | |||
| 560 | size_t GetBufSize() const { return m_bufdata->m_size; } | |||
| 561 | size_t GetDataLen() const { return m_bufdata->m_len; } | |||
| 562 | ||||
| 563 | bool IsEmpty() const { return GetDataLen() == 0; } | |||
| 564 | ||||
| 565 | void SetBufSize(size_t size) { m_bufdata->ResizeIfNeeded(size); } | |||
| 566 | void SetDataLen(size_t len) | |||
| 567 | { | |||
| 568 | wxASSERT(len <= m_bufdata->m_size)do { if ( len <= m_bufdata->m_size ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 568 , __FUNCTION__, "len <= m_bufdata->m_size", (const char *)__null), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 569 | m_bufdata->m_len = len; | |||
| 570 | } | |||
| 571 | ||||
| 572 | void Clear() { SetDataLen(0); } | |||
| 573 | ||||
| 574 | // Ensure the buffer is big enough and return a pointer to it | |||
| 575 | void *GetWriteBuf(size_t sizeNeeded) | |||
| 576 | { | |||
| 577 | m_bufdata->ResizeIfNeeded(sizeNeeded); | |||
| 578 | return m_bufdata->m_data; | |||
| 579 | } | |||
| 580 | ||||
| 581 | // Update the length after the write | |||
| 582 | void UngetWriteBuf(size_t sizeUsed) { SetDataLen(sizeUsed); } | |||
| 583 | ||||
| 584 | // Like the above, but appends to the buffer | |||
| 585 | void *GetAppendBuf(size_t sizeNeeded) | |||
| 586 | { | |||
| 587 | m_bufdata->ResizeIfNeeded(m_bufdata->m_len + sizeNeeded); | |||
| 588 | return (char*)m_bufdata->m_data + m_bufdata->m_len; | |||
| 589 | } | |||
| 590 | ||||
| 591 | // Update the length after the append | |||
| 592 | void UngetAppendBuf(size_t sizeUsed) | |||
| 593 | { | |||
| 594 | SetDataLen(m_bufdata->m_len + sizeUsed); | |||
| 595 | } | |||
| 596 | ||||
| 597 | // Other ways to append to the buffer | |||
| 598 | void AppendByte(char data) | |||
| 599 | { | |||
| 600 | wxCHECK_RET( m_bufdata->m_data, wxT("invalid wxMemoryBuffer") )if ( m_bufdata->m_data ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/buffer.h", 600 , __FUNCTION__, "\"m_bufdata->m_data\"", L"invalid wxMemoryBuffer" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct600; | |||
| 601 | ||||
| 602 | m_bufdata->ResizeIfNeeded(m_bufdata->m_len + 1); | |||
| 603 | *(((char*)m_bufdata->m_data) + m_bufdata->m_len) = data; | |||
| 604 | m_bufdata->m_len += 1; | |||
| 605 | } | |||
| 606 | ||||
| 607 | void AppendData(const void *data, size_t len) | |||
| 608 | { | |||
| 609 | memcpy(GetAppendBuf(len), data, len); | |||
| 610 | UngetAppendBuf(len); | |||
| 611 | } | |||
| 612 | ||||
| 613 | operator const char *() const { return (const char*)GetData(); } | |||
| 614 | ||||
| 615 | // gives up ownership of data, returns the pointer; after this call, | |||
| 616 | // data isn't freed by the buffer and its content is resent to empty | |||
| 617 | void *release() | |||
| 618 | { | |||
| 619 | return m_bufdata->release(); | |||
| 620 | } | |||
| 621 | ||||
| 622 | private: | |||
| 623 | wxMemoryBufferData* m_bufdata; | |||
| 624 | }; | |||
| 625 | ||||
| 626 | // ---------------------------------------------------------------------------- | |||
| 627 | // template class for any kind of data | |||
| 628 | // ---------------------------------------------------------------------------- | |||
| 629 | ||||
| 630 | // TODO | |||
| 631 | ||||
| 632 | #endif // _WX_BUFFER_H |