Changeset 90828 in vbox for trunk/src/VBox/Main/src-all
- Timestamp:
- Aug 24, 2021 9:44:46 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 146463
- Location:
- trunk/src/VBox/Main/src-all
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-all/QMTranslatorImpl.cpp
r85212 r90828 23 23 #include <iprt/file.h> 24 24 #include <iprt/asm.h> 25 #include <iprt/string.h> 26 #include <iprt/strcache.h> 25 27 #include <VBox/com/string.h> 26 28 #include <VBox/log.h> … … 47 49 class QMBytesStream 48 50 { 49 size_t m_cbSize;51 size_t m_cbSize; 50 52 const uint8_t * const m_dataStart; 51 53 const uint8_t *m_iter; 52 54 const uint8_t *m_end; 53 54 /* Function stub for transform method */55 static uint16_t func_BE2H_U16(uint16_t value)56 {57 return RT_BE2H_U16(value);58 }59 55 60 56 public: … … 94 90 uint32_t size = read32(); 95 91 checkSize(size); 96 if (size & 1) throw QMException("Incorrect string size"); 97 std::vector<uint16_t> wstr; 98 wstr.reserve(size / 2); 99 100 /* We cannot convert to host endianess without copying the data 101 * since the file might be mapped to the memory and any memory 102 * change will lead to the change of the file. */ 103 std::transform(reinterpret_cast<const uint16_t *>(m_iter), 104 reinterpret_cast<const uint16_t *>(m_iter + size), 105 std::back_inserter(wstr), 106 func_BE2H_U16); 92 if (size & 1) 93 throw QMException("Incorrect string size"); 94 95 /* UTF-16 can encode up to codepoint U+10ffff, which UTF-8 needs 4 bytes 96 to encode, so reserve twice the size plus a terminator for the result. */ 97 com::Utf8Str result; 98 result.reserve(size * 2 + 1); 99 char *pszStr = result.mutableRaw(); 100 int rc = RTUtf16BigToUtf8Ex((PCRTUTF16)m_iter, size >> 1, &pszStr, result.capacity(), NULL); 101 if (RT_SUCCESS(rc)) 102 result.jolt(); 103 else 104 throw QMException("Translation from UTF-16 to UTF-8 failed"); 105 107 106 m_iter += size; 108 return com::Utf8Str((CBSTR) &wstr.front(), wstr.size()); 109 } 110 111 /** Reads string in one-byte encoding. 112 * The string is assumed to be in ISO-8859-1 encoding */ 107 return result; 108 } 109 110 /** 111 * Reads a string, forcing UTF-8 encoding. 112 */ 113 113 inline com::Utf8Str readString() 114 114 { 115 115 uint32_t size = read32(); 116 116 checkSize(size); 117 117 118 com::Utf8Str result(reinterpret_cast<const char *>(m_iter), size); 119 if (size > 0) 120 { 121 RTStrPurgeEncoding(result.mutableRaw()); 122 result.jolt(); 123 } 124 118 125 m_iter += size; 119 126 return result; 127 } 128 129 /** 130 * Reads memory block 131 * Returns number of bytes read 132 */ 133 inline uint32_t read(char *bBuf, uint32_t cbSize) 134 { 135 if (!bBuf || !cbSize) 136 return 0; 137 cbSize = RT_MIN(cbSize, (uint32_t)(m_end - m_iter)); 138 memcpy(bBuf, m_iter, cbSize); 139 m_iter += cbSize; 140 return cbSize; 120 141 } 121 142 … … 148 169 { 149 170 size_t cbLeft = (size_t)(m_end - m_iter); 150 if (cbLeft <= offSkip)171 if (cbLeft >= offSkip) 151 172 m_iter += offSkip; 152 173 else … … 166 187 class QMTranslator_Impl 167 188 { 168 struct QMMessage 189 /** Used while parsing */ 190 struct QMMessageParse 169 191 { 170 192 /* Everything is in UTF-8 */ 193 std::vector<com::Utf8Str> astrTranslations; 171 194 com::Utf8Str strContext; 172 com::Utf8Str strTranslation;173 195 com::Utf8Str strComment; 174 196 com::Utf8Str strSource; 175 uint32_t hash; 176 QMMessage() : hash(0) {} 197 198 QMMessageParse() {} 199 }; 200 201 struct QMMessage 202 { 203 const char *pszContext; 204 const char *pszSource; 205 const char *pszComment; 206 std::vector<const char *> vecTranslations; 207 uint32_t hash; 208 209 QMMessage() : pszContext(NULL), pszSource(NULL), pszComment(NULL), hash(0) 210 {} 211 212 QMMessage(RTSTRCACHE hStrCache, const QMMessageParse &rSrc) 213 : pszContext(addStr(hStrCache, rSrc.strContext)) 214 , pszSource(addStr(hStrCache, rSrc.strSource)) 215 , pszComment(addStr(hStrCache, rSrc.strComment)) 216 , hash(RTStrHash1(pszSource)) 217 { 218 for (size_t i = 0; i < rSrc.astrTranslations.size(); i++) 219 vecTranslations.push_back(addStr(hStrCache, rSrc.astrTranslations[i])); 220 } 221 222 /** Helper. */ 223 static const char *addStr(RTSTRCACHE hStrCache, const com::Utf8Str &rSrc) 224 { 225 if (rSrc.isNotEmpty()) 226 { 227 const char *psz = RTStrCacheEnterN(hStrCache, rSrc.c_str(), rSrc.length()); 228 if (RT_LIKELY(psz)) 229 return psz; 230 throw std::bad_alloc(); 231 } 232 return NULL; 233 } 234 177 235 }; 178 236 … … 182 240 uint32_t offset; 183 241 184 HashOffset(uint32_t _hash = 0, uint32_t _offs = 0) : hash(_hash), offset(_offs) {}242 HashOffset(uint32_t a_hash = 0, uint32_t a_offs = 0) : hash(a_hash), offset(a_offs) {} 185 243 186 244 bool operator<(const HashOffset &obj) const … … 194 252 typedef QMHashSet::const_iterator QMHashSetConstIter; 195 253 typedef std::vector<QMMessage> QMMessageArray; 196 197 QMHashSet m_hashSet; 254 typedef std::vector<uint8_t> QMByteArray; 255 256 QMHashSet m_hashSet; 198 257 QMMessageArray m_messageArray; 258 QMByteArray m_pluralRules; 199 259 200 260 public: 201 261 202 262 QMTranslator_Impl() {} 263 264 enum PluralOpCodes 265 { 266 Pl_Eq = 0x01, 267 Pl_Lt = 0x02, 268 Pl_Leq = 0x03, 269 Pl_Between = 0x04, 270 271 Pl_OpMask = 0x07, 272 273 Pl_Not = 0x08, 274 Pl_Mod10 = 0x10, 275 Pl_Mod100 = 0x20, 276 Pl_Lead1000 = 0x40, 277 278 Pl_And = 0xFD, 279 Pl_Or = 0xFE, 280 Pl_NewRule = 0xFF, 281 282 Pl_LMask = 0x80, 283 }; 284 285 /* 286 * Rules format: 287 * <O><2>[<3>][<&&><O><2>[<3>]]...[<||><O><2>[<3>][<&&><O><2>[<3>]]...]...[<New><O>...]... 288 * where: 289 * <O> - OpCode 290 * <2> - Second operand 291 * <3> - Third operand 292 * <&&> - 'And' operation 293 * <||> - 'Or' operation 294 * <New> - Start of rule for next plural form 295 * Rules are ordered by plural forms, i.e: 296 * <rule for first form (i.e. single)><New><rule for next form>... 297 */ 298 bool checkPlural(const QMByteArray &aRules) const 299 { 300 if (aRules.empty()) 301 return true; 302 303 uint32_t iPos = 0; 304 do { 305 uint8_t bOpCode = aRules[iPos]; 306 307 /* Invalid place of And/Or/NewRule */ 308 if (bOpCode & Pl_LMask) 309 return false; 310 311 /* 2nd operand */ 312 iPos++; 313 314 /* 2nd operand missing */ 315 if (iPos == aRules.size()) 316 return false; 317 318 /* Invalid OpCode */ 319 if ((bOpCode & Pl_OpMask) == 0) 320 return false; 321 322 if ((bOpCode & Pl_OpMask) == Pl_Between) 323 { 324 /* 3rd operand */ 325 iPos++; 326 327 /* 3rd operand missing */ 328 if (iPos == aRules.size()) 329 return false; 330 } 331 332 /* And/Or/NewRule */ 333 iPos++; 334 335 /* All rules checked */ 336 if (iPos == aRules.size()) 337 return true; 338 339 } while ( ( (aRules[iPos] == Pl_And) 340 || (aRules[iPos] == Pl_Or) 341 || (aRules[iPos] == Pl_NewRule)) 342 && ++iPos != aRules.size()); 343 344 return false; 345 } 346 347 int plural(int aNum) const 348 { 349 if (aNum < 1 || m_pluralRules.empty()) 350 return 0; 351 352 int iPluralNumber = 0; 353 uint32_t iPos = 0; 354 355 /* Rules loop */ 356 for (;;) 357 { 358 bool fOr = false; 359 /* 'Or' loop */ 360 for (;;) 361 { 362 bool fAnd = true; 363 /* 'And' loop */ 364 for (;;) 365 { 366 int iOpCode = m_pluralRules[iPos++]; 367 int iOpLeft = aNum; 368 if (iOpCode & Pl_Mod10) 369 iOpLeft %= 10; 370 else if (iOpCode & Pl_Mod100) 371 iOpLeft %= 100; 372 else if (iOpLeft & Pl_Lead1000) 373 { 374 while (iOpLeft >= 1000) 375 iOpLeft /= 1000; 376 } 377 int iOpRight = m_pluralRules[iPos++]; 378 int iOp = iOpCode & Pl_OpMask; 379 int iOpRight1 = 0; 380 if (iOp == Pl_Between) 381 iOpRight1 = m_pluralRules[iPos++]; 382 383 bool fResult = (iOp == Pl_Eq && iOpLeft == iOpRight) 384 || (iOp == Pl_Lt && iOpLeft < iOpRight) 385 || (iOp == Pl_Leq && iOpLeft <= iOpRight) 386 || (iOp == Pl_Between && iOpLeft >= iOpRight && iOpLeft <= iOpRight1); 387 if (iOpCode & Pl_Not) 388 fResult = !fResult; 389 390 fAnd = fAnd && fResult; 391 if (iPos == m_pluralRules.size() || m_pluralRules[iPos] != Pl_And) 392 break; 393 iPos++; 394 } 395 fOr = fOr || fAnd; 396 if (iPos == m_pluralRules.size() || m_pluralRules[iPos] != Pl_Or) 397 break; 398 iPos++; 399 } 400 if (fOr) 401 return iPluralNumber; 402 403 /* Qt returns last plural number if none of rules are match. */ 404 iPluralNumber++; 405 406 if (iPos >= m_pluralRules.size()) 407 return iPluralNumber; 408 409 iPos++; // Skip Pl_NewRule 410 } 411 } 203 412 204 413 const char *translate(const char *pszContext, 205 414 const char *pszSource, 206 const char *pszDisamb) const 415 const char *pszDisamb, 416 const int aNum) const 207 417 { 208 418 QMHashSetConstIter iter; 209 419 QMHashSetConstIter lowerIter, upperIter; 210 420 211 do { 212 uint32_t hash = calculateHash(pszSource, pszDisamb); 213 lowerIter = m_hashSet.lower_bound(HashOffset(hash, 0)); 214 upperIter = m_hashSet.upper_bound(HashOffset(hash, UINT32_MAX)); 215 421 /* As turned out, comments (pszDisamb) are not kept always in result qm file 422 * Therefore, exclude them from the hash */ 423 uint32_t hash = RTStrHash1(pszSource); 424 lowerIter = m_hashSet.lower_bound(HashOffset(hash, 0)); 425 upperIter = m_hashSet.upper_bound(HashOffset(hash, UINT32_MAX)); 426 427 /* 428 * Check different combinations with and without context and 429 * disambiguation. This can help us to find the translation even 430 * if context or disambiguation are not know or properly defined. 431 */ 432 const char *apszCtx[] = {pszContext, pszContext, NULL, NULL}; 433 const char *apszDisabm[] = {pszDisamb, NULL, pszDisamb, NULL}; 434 AssertCompile(RT_ELEMENTS(apszCtx) == RT_ELEMENTS(apszDisabm)); 435 436 for (size_t i = 0; i < RT_ELEMENTS(apszCtx); ++i) 437 { 216 438 for (iter = lowerIter; iter != upperIter; ++iter) 217 439 { 218 440 const QMMessage &message = m_messageArray[iter->offset]; 219 if ((!pszContext || !*pszContext || message.strContext == pszContext) && 220 message.strSource == pszSource && 221 ((pszDisamb && !*pszDisamb) || message.strComment == pszDisamb)) 222 break; 441 if ( RTStrCmp(message.pszSource, pszSource) == 0 442 && (!apszCtx[i] || !*apszCtx[i] || RTStrCmp(message.pszContext, apszCtx[i]) == 0) 443 && (!apszDisabm[i] || !*apszDisabm[i] || RTStrCmp(message.pszComment, apszDisabm[i]) == 0 )) 444 { 445 const std::vector<const char *> &vecTranslations = m_messageArray[iter->offset].vecTranslations; 446 size_t idxPlural = plural(aNum); 447 return vecTranslations[RT_MIN(idxPlural, vecTranslations.size() - 1)]; 448 } 223 449 } 224 225 /* Try without disambiguating comment if it isn't empty */ 226 if (pszDisamb) 227 { 228 if (!*pszDisamb) pszDisamb = 0; 229 else pszDisamb = ""; 230 } 231 232 } while (iter == upperIter && pszDisamb); 233 234 return (iter != upperIter ? m_messageArray[iter->offset].strTranslation.c_str() : ""); 235 } 236 237 void load(QMBytesStream &stream) 450 } 451 452 return pszSource; 453 } 454 455 void load(QMBytesStream &stream, RTSTRCACHE hStrCache) 238 456 { 239 457 /* Load into local variables. If we failed during the load, … … 241 459 QMHashSet hashSet; 242 460 QMMessageArray messageArray; 461 QMByteArray pluralRules; 243 462 244 463 stream.checkMagic(); … … 255 474 { 256 475 case Messages: 257 parseMessages(stream, &hashSet, &messageArray, sLen);476 parseMessages(stream, hStrCache, &hashSet, &messageArray, sLen); 258 477 break; 259 478 case Hashes: 260 479 /* Only get size information to speed-up vector filling 261 480 * if Hashes section goes in the file before Message section */ 262 m_messageArray.reserve(sLen >> 3); 263 RT_FALL_THRU(); 264 case Context: 481 if (messageArray.empty()) 482 messageArray.reserve(sLen >> 3); 483 stream.seek(sLen); 484 break; 485 case NumerusRules: 486 { 487 pluralRules.resize(sLen); 488 uint32_t cbSize = stream.read((char *)&pluralRules[0], sLen); 489 if (cbSize < sLen) 490 throw QMException("Incorrect section size"); 491 if (!checkPlural(pluralRules)) 492 pluralRules.erase(pluralRules.begin(), pluralRules.end()); 493 break; 494 } 495 case Contexts: 496 case Dependencies: 497 case Language: 265 498 stream.seek(sLen); 266 499 break; … … 269 502 } 270 503 } 504 271 505 /* Store the data into member variables. 272 506 * The following functions never generate exceptions */ 273 507 m_hashSet.swap(hashSet); 274 508 m_messageArray.swap(messageArray); 509 m_pluralRules.swap(pluralRules); 275 510 } 276 511 … … 280 515 enum SectionType 281 516 { 282 Hashes = 0x42, 283 Messages = 0x69, 284 Contexts = 0x2f 517 Contexts = 0x2f, 518 Hashes = 0x42, 519 Messages = 0x69, 520 NumerusRules = 0x88, 521 Dependencies = 0x96, 522 Language = 0xa7 285 523 }; 286 524 … … 291 529 Translation = 3, 292 530 Context16 = 4, 293 Hash = 5,531 Obsolete1 = 5, /**< was Hash */ 294 532 SourceText = 6, 295 533 Context = 7, … … 298 536 299 537 /* Read messages from the stream. */ 300 static void parseMessages(QMBytesStream &stream, QMHashSet * const hashSet, QMMessageArray * const messageArray, size_t cbSize) 538 static void parseMessages(QMBytesStream &stream, RTSTRCACHE hStrCache, QMHashSet * const hashSet, 539 QMMessageArray * const messageArray, size_t cbSize) 301 540 { 302 541 stream.setEnd(stream.tellPos() + cbSize); … … 304 543 while (!stream.hasFinished()) 305 544 { 306 QMMessage message; 307 HashOffset hashOffs; 308 309 parseMessageRecord(stream, &message); 310 if (!message.hash) 311 message.hash = calculateHash(message.strSource.c_str(), message.strComment.c_str()); 312 313 hashOffs.hash = message.hash; 314 hashOffs.offset = cMessage++; 315 316 hashSet->insert(hashOffs); 317 messageArray->push_back(message); 545 /* Process the record. Skip anything that doesn't have a source 546 string or any valid translations. Using C++ strings for temporary 547 storage here, as we don't want to pollute the cache we bogus strings 548 in case of duplicate sub-records or invalid records. */ 549 QMMessageParse ParsedMsg; 550 parseMessageRecord(stream, &ParsedMsg); 551 if ( ParsedMsg.astrTranslations.size() > 0 552 && ParsedMsg.strSource.isNotEmpty()) 553 { 554 /* Copy the strings over into the string cache and a hashed QMMessage, 555 before adding it to the result. */ 556 QMMessage HashedMsg(hStrCache, ParsedMsg); 557 hashSet->insert(HashOffset(HashedMsg.hash, cMessage++)); 558 messageArray->push_back(HashedMsg); 559 560 } 561 /*else: wtf? */ 318 562 } 319 563 stream.setEnd(); … … 321 565 322 566 /* Parse one message from the stream */ 323 static void parseMessageRecord(QMBytesStream &stream, QMMessage * const message)567 static void parseMessageRecord(QMBytesStream &stream, QMMessageParse * const message) 324 568 { 325 569 while (!stream.hasFinished()) … … 336 580 break; 337 581 case Translation: 338 { 339 com::Utf8Str str = stream.readUtf16String(); 340 message->strTranslation.swap(str); 341 break; 342 } 343 case Hash: 344 message->hash = stream.read32(); 582 message->astrTranslations.push_back(stream.readUtf16String()); 345 583 break; 346 584 347 585 case SourceText: 348 { 349 com::Utf8Str str = stream.readString(); 350 message->strSource.swap(str); 351 break; 352 } 586 message->strSource = stream.readString(); 587 break; 353 588 354 589 case Context: 355 { 356 com::Utf8Str str = stream.readString(); 357 message->strContext.swap(str); 358 break; 359 } 590 message->strContext = stream.readString(); 591 break; 360 592 361 593 case Comment: 362 { 363 com::Utf8Str str = stream.readString(); 364 message->strComment.swap(str); 365 break; 366 } 594 message->strComment = stream.readString(); 595 break; 367 596 368 597 default: 369 /* Ignore unknown block */370 LogRel(("QMTranslator::parseMessageRecord(): Unk ownmessage block %x\n", type));598 /* Ignore unknown/obsolete block */ 599 LogRel(("QMTranslator::parseMessageRecord(): Unknown/obsolete message block %x\n", type)); 371 600 break; 372 601 } 373 602 } 374 603 } 375 376 /* Defines the so called `hashpjw' function by P.J. Weinberger377 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,378 1986, 1987 Bell Telephone Laboratories, Inc.] */379 static uint32_t calculateHash(const char *pszStr1, const char *pszStr2 = 0)380 {381 uint32_t hash = 0, g;382 383 for (const char *pszStr = pszStr1; pszStr != pszStr2; pszStr = pszStr2)384 for (; pszStr && *pszStr; pszStr++)385 {386 hash = (hash << 4) + static_cast<uint8_t>(*pszStr);387 388 if ((g = hash & 0xf0000000ul) != 0)389 {390 hash ^= g >> 24;391 hash ^= g;392 }393 }394 395 return (hash != 0 ? hash : 1);396 }397 604 }; 398 605 399 606 /* Inteface functions implementation */ 400 QMTranslator::QMTranslator() : _impl(new QMTranslator_Impl) {} 401 402 QMTranslator::~QMTranslator() { delete _impl; } 403 404 const char *QMTranslator::translate(const char *pszContext, const char *pszSource, const char *pszDisamb) const throw() 607 QMTranslator::QMTranslator() : m_impl(new QMTranslator_Impl) {} 608 609 QMTranslator::~QMTranslator() { delete m_impl; } 610 611 const char *QMTranslator::translate(const char *pszContext, const char *pszSource, 612 const char *pszDisamb, const int aNum) const throw() 405 613 { 406 return _impl->translate(pszContext, pszSource, pszDisamb);614 return m_impl->translate(pszContext, pszSource, pszDisamb, aNum); 407 615 } 408 616 409 /* The function is noexcept for now but it may be changed 410 * to throw exceptions if required to catch them in another 411 * place. */ 412 int QMTranslator::load(const char *pszFilename) throw() 617 int QMTranslator::load(const char *pszFilename, RTSTRCACHE hStrCache) RT_NOEXCEPT 413 618 { 414 619 /* To free safely the file in case of exception */ … … 437 642 { 438 643 QMBytesStream stream(loader.data, loader.cbSize); 439 _impl->load(stream);644 m_impl->load(stream, hStrCache); 440 645 } 441 646 return loader.rc; -
trunk/src/VBox/Main/src-all/TextScript.cpp
r82968 r90828 53 53 } 54 54 else 55 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc);55 hrc = mpSetError->setErrorVrc(vrc, tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc); 56 56 return hrc; 57 57 } … … 94 94 } 95 95 96 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc);96 hrc = mpSetError->setErrorVrc(vrc, tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc); 97 97 } 98 98 else 99 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error reading '%s': %Rrc"), pszFilename, vrc);99 hrc = mpSetError->setErrorVrc(vrc, tr("Error reading '%s': %Rrc"), pszFilename, vrc); 100 100 mStrScriptFullContent.setNull(); 101 101 } 102 102 else 103 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to allocate memory (%'RU64 bytes) for '%s'"),103 hrc = mpSetError->setErrorVrc(vrc, tr("Failed to allocate memory (%'RU64 bytes) for '%s'"), 104 104 cbFile, pszFilename); 105 105 } 106 106 else if (RT_SUCCESS(vrc)) 107 hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG, 108 mpSetError->tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile); 107 hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG, tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile); 109 108 else 110 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("RTVfsFileQuerySize failed (%Rrc)"), vrc);109 hrc = mpSetError->setErrorVrc(vrc, tr("RTVfsFileQuerySize failed (%Rrc)"), vrc); 111 110 return hrc; 112 111 } … … 179 178 RTFileClose(hFile); 180 179 RTFileDelete(pszFilename); 181 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc);180 hrc = mpSetError->setErrorVrc(vrc, tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc); 182 181 } 183 182 else 184 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);183 hrc = mpSetError->setErrorVrc(vrc, tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc); 185 184 } 186 185 return hrc; -
trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp
r83787 r90828 34 34 #include "AutoCaller.h" 35 35 #include "VirtualBoxErrorInfoImpl.h" 36 #include "VirtualBoxTranslator.h" 36 37 #include "Global.h" 37 38 #include "LoggingNew.h" … … 226 227 catch (const RTCError &err) // includes all XML exceptions 227 228 { 228 return setErrorInternal (E_FAIL, aThis->getClassIID(), aThis->getComponentName(),229 Utf8StrFmt(tr("%s.\n%s[%d] (%s)"),230 err.what(),231 pszFile, iLine, pszFunction).c_str(),232 false /* aWarning */,233 true /* aLogIt */);229 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), 230 false /* aWarning */, 231 true /* aLogIt */, 232 0 /* aResultDetail */, 233 tr("%s.\n%s[%d] (%s)"), 234 err.what(), pszFile, iLine, pszFunction); 234 235 } 235 236 catch (const std::exception &err) 236 237 { 237 return setErrorInternal (E_FAIL, aThis->getClassIID(), aThis->getComponentName(),238 Utf8StrFmt(tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),239 err.what(), typeid(err).name(),240 pszFile, iLine, pszFunction).c_str(),241 false /* aWarning */,242 true /* aLogIt */);238 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), 239 false /* aWarning */, 240 true /* aLogIt */, 241 0 /* aResultDetail */, 242 tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"), 243 err.what(), typeid(err).name(), pszFile, iLine, pszFunction); 243 244 } 244 245 catch (...) 245 246 { 246 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), 247 Utf8StrFmt(tr("Unknown exception\n%s[%d] (%s)"), 248 pszFile, iLine, pszFunction).c_str(), 249 false /* aWarning */, 250 true /* aLogIt */); 247 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), 248 false /* aWarning */, 249 true /* aLogIt */, 250 0 /* aResultDetail */, 251 tr("Unknown exception\n%s[%d] (%s)"), 252 pszFile, iLine, pszFunction); 251 253 } 252 254 … … 257 259 #endif 258 260 } 261 259 262 260 263 /** … … 266 269 * than an error. 267 270 * 271 * @param aResultCode 272 * @param aIID 273 * @param aComponent 274 * @param aWarning 275 * @param aLogIt 276 * @param aResultDetail 277 * @param aText 278 */ 279 /* static */ 280 HRESULT VirtualBoxBase::setErrorInternalF(HRESULT aResultCode, 281 const GUID &aIID, 282 const char *aComponent, 283 bool aWarning, 284 bool aLogIt, 285 LONG aResultDetail, 286 const char *aText, ...) 287 { 288 va_list va; 289 va_start(va, aText); 290 HRESULT hres = setErrorInternalV(aResultCode, aIID, aComponent, aText, va, 291 aWarning, aLogIt, aResultDetail); 292 va_end(va); 293 return hres; 294 } 295 296 /** 297 * Sets error info for the current thread. This is an internal function that 298 * gets eventually called by all public variants. If @a aWarning is 299 * @c true, then the highest (31) bit in the @a aResultCode value which 300 * indicates the error severity is reset to zero to make sure the receiver will 301 * recognize that the created error info object represents a warning rather 302 * than an error. 303 * 268 304 * @param aResultCode 269 305 * @param aIID 270 306 * @param pcszComponent 271 307 * @param aText 308 * @param va 272 309 * @param aWarning 273 310 * @param aLogIt … … 275 312 */ 276 313 /* static */ 277 HRESULT VirtualBoxBase::setErrorInternal(HRESULT aResultCode, 278 const GUID &aIID, 279 const char *pcszComponent, 280 Utf8Str aText, 281 bool aWarning, 282 bool aLogIt, 283 LONG aResultDetail /* = 0*/) 314 HRESULT VirtualBoxBase::setErrorInternalV(HRESULT aResultCode, 315 const GUID &aIID, 316 const char *aComponent, 317 const char *aText, 318 va_list aArgs, 319 bool aWarning, 320 bool aLogIt, 321 LONG aResultDetail /* = 0*/) 284 322 { 285 323 /* whether multi-error mode is turned on */ 286 324 bool preserve = MultiResult::isMultiEnabled(); 287 325 326 com::Utf8Str strText; 288 327 if (aLogIt) 289 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%s}, preserve=%RTbool aResultDetail=%d\n", 328 { 329 strText = trSource(aText); 330 va_list va2; 331 va_copy(va2, aArgs); 332 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%N}, preserve=%RTbool aResultDetail=%d\n", 290 333 aWarning ? "WARNING" : "ERROR", 291 334 aResultCode, 292 335 aResultCode, 293 336 &aIID, 294 pcszComponent, 295 aText.c_str(), 337 aComponent, 338 strText.c_str(), 339 &va2, 296 340 preserve, 297 341 aResultDetail)); 342 va_end(va2); 343 } 298 344 299 345 /* these are mandatory, others -- not */ … … 308 354 HRESULT rc = S_OK; 309 355 310 if (aText .isEmpty())356 if (aText == NULL || aText[0] == '\0') 311 357 { 312 358 /* Some default info */ 313 359 switch (aResultCode) 314 360 { 315 case E_INVALIDARG: aText = "A parameter has an invalid value"; break; 316 case E_POINTER: aText = "A parameter is an invalid pointer"; break; 317 case E_UNEXPECTED: aText = "The result of the operation is unexpected"; break; 318 case E_ACCESSDENIED: aText = "The access to an object is not allowed"; break; 319 case E_OUTOFMEMORY: aText = "The allocation of new memory failed"; break; 320 case E_NOTIMPL: aText = "The requested operation is not implemented"; break; 321 case E_NOINTERFACE: aText = "The requested interface is not implemented"; break; 322 case E_FAIL: aText = "A general error occurred"; break; 323 case E_ABORT: aText = "The operation was canceled"; break; 324 case VBOX_E_OBJECT_NOT_FOUND: aText = "Object corresponding to the supplied arguments does not exist"; break; 325 case VBOX_E_INVALID_VM_STATE: aText = "Current virtual machine state prevents the operation"; break; 326 case VBOX_E_VM_ERROR: aText = "Virtual machine error occurred attempting the operation"; break; 327 case VBOX_E_FILE_ERROR: aText = "File not accessible or erroneous file contents"; break; 328 case VBOX_E_IPRT_ERROR: aText = "Runtime subsystem error"; break; 329 case VBOX_E_PDM_ERROR: aText = "Pluggable Device Manager error"; break; 330 case VBOX_E_INVALID_OBJECT_STATE: aText = "Current object state prohibits operation"; break; 331 case VBOX_E_HOST_ERROR: aText = "Host operating system related error"; break; 332 case VBOX_E_NOT_SUPPORTED: aText = "Requested operation is not supported"; break; 333 case VBOX_E_XML_ERROR: aText = "Invalid XML found"; break; 334 case VBOX_E_INVALID_SESSION_STATE: aText = "Current session state prohibits operation"; break; 335 case VBOX_E_OBJECT_IN_USE: aText = "Object being in use prohibits operation"; break; 336 case VBOX_E_PASSWORD_INCORRECT: aText = "Incorrect password provided"; break; 337 default: aText = "Unknown error"; break; 338 } 361 case E_INVALIDARG: strText = "A parameter has an invalid value"; break; 362 case E_POINTER: strText = "A parameter is an invalid pointer"; break; 363 case E_UNEXPECTED: strText = "The result of the operation is unexpected"; break; 364 case E_ACCESSDENIED: strText = "The access to an object is not allowed"; break; 365 case E_OUTOFMEMORY: strText = "The allocation of new memory failed"; break; 366 case E_NOTIMPL: strText = "The requested operation is not implemented"; break; 367 case E_NOINTERFACE: strText = "The requested interface is not implemented"; break; 368 case E_FAIL: strText = "A general error occurred"; break; 369 case E_ABORT: strText = "The operation was canceled"; break; 370 case VBOX_E_OBJECT_NOT_FOUND: strText = "Object corresponding to the supplied arguments does not exist"; break; 371 case VBOX_E_INVALID_VM_STATE: strText = "Current virtual machine state prevents the operation"; break; 372 case VBOX_E_VM_ERROR: strText = "Virtual machine error occurred attempting the operation"; break; 373 case VBOX_E_FILE_ERROR: strText = "File not accessible or erroneous file contents"; break; 374 case VBOX_E_IPRT_ERROR: strText = "Runtime subsystem error"; break; 375 case VBOX_E_PDM_ERROR: strText = "Pluggable Device Manager error"; break; 376 case VBOX_E_INVALID_OBJECT_STATE: strText = "Current object state prohibits operation"; break; 377 case VBOX_E_HOST_ERROR: strText = "Host operating system related error"; break; 378 case VBOX_E_NOT_SUPPORTED: strText = "Requested operation is not supported"; break; 379 case VBOX_E_XML_ERROR: strText = "Invalid XML found"; break; 380 case VBOX_E_INVALID_SESSION_STATE: strText = "Current session state prohibits operation"; break; 381 case VBOX_E_OBJECT_IN_USE: strText = "Object being in use prohibits operation"; break; 382 case VBOX_E_PASSWORD_INCORRECT: strText = "Incorrect password provided"; break; 383 default: strText = "Unknown error"; break; 384 } 385 } 386 else 387 { 388 va_list va2; 389 va_copy(va2, aArgs); 390 strText = com::Utf8StrFmt("%N", aText, &va2); 391 va_end(va2); 339 392 } 340 393 … … 373 426 374 427 /* set the current error info and preserve the previous one if any */ 375 rc = info->initEx(aResultCode, aResultDetail, aIID, pcszComponent, aText, curInfo);428 rc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, strText, curInfo); 376 429 if (FAILED(rc)) break; 377 430 … … 417 470 418 471 /* set the current error info and preserve the previous one if any */ 419 rc = info->initEx(aResultCode, aResultDetail, aIID, pcszComponent, Bstr(aText), curInfo);472 rc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, Bstr(strText), curInfo); 420 473 if (FAILED(rc)) break; 421 474 … … 459 512 HRESULT VirtualBoxBase::setError(HRESULT aResultCode) 460 513 { 461 return setErrorInternal(aResultCode, 462 this->getClassIID(), 463 this->getComponentName(), 464 "", 465 false /* aWarning */, 466 true /* aLogIt */); 514 return setErrorInternalF(aResultCode, 515 this->getClassIID(), 516 this->getComponentName(), 517 false /* aWarning */, 518 true /* aLogIt */, 519 0 /* aResultDetail */, 520 NULL); 467 521 } 468 522 … … 480 534 va_list args; 481 535 va_start(args, pcsz); 482 HRESULT rc = setErrorInternal (aResultCode,483 this->getClassIID(),484 this->getComponentName(),485 Utf8Str(pcsz, args),486 false /* aWarning */,487 true /* aLogIt */);536 HRESULT rc = setErrorInternalV(aResultCode, 537 this->getClassIID(), 538 this->getComponentName(), 539 pcsz, args, 540 false /* aWarning */, 541 true /* aLogIt */); 488 542 va_end(args); 489 543 return rc; … … 628 682 HRESULT VirtualBoxBase::setErrorVrc(int vrc) 629 683 { 630 return setErrorInternal (Global::vboxStatusCodeToCOM(vrc),631 this->getClassIID(),632 this->getComponentName(),633 Utf8StrFmt("%Rrc", vrc),634 false /* aWarning*/,635 true /* aLogIt*/,636 vrc /* aResultDetail */);684 return setErrorInternalF(Global::vboxStatusCodeToCOM(vrc), 685 this->getClassIID(), 686 this->getComponentName(), 687 false /* aWarning */, 688 true /* aLogIt */, 689 vrc /* aResultDetail */, 690 Utf8StrFmt("%Rrc", vrc).c_str()); 637 691 } 638 692 … … 651 705 va_list va; 652 706 va_start(va, pcszMsgFmt); 653 HRESULT hrc = setErrorInternal (Global::vboxStatusCodeToCOM(vrc),654 this->getClassIID(),655 this->getComponentName(),656 Utf8Str(pcszMsgFmt, va),657 false /* aWarning */,658 true /* aLogIt */,659 vrc /* aResultDetail */);707 HRESULT hrc = setErrorInternalV(Global::vboxStatusCodeToCOM(vrc), 708 this->getClassIID(), 709 this->getComponentName(), 710 pcszMsgFmt, va, 711 false /* aWarning */, 712 true /* aLogIt */, 713 vrc /* aResultDetail */); 660 714 va_end(va); 661 715 return hrc; … … 676 730 HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc) 677 731 { 678 return setErrorInternal (hrc,679 this->getClassIID(),680 this->getComponentName(),681 Utf8StrFmt("%Rrc", vrc),682 false /* aWarning*/,683 true /* aLogIt*/,684 vrc /* aResultDetail */);732 return setErrorInternalF(hrc, 733 this->getClassIID(), 734 this->getComponentName(), 735 false /* aWarning */, 736 true /* aLogIt */, 737 vrc /* aResultDetail */, 738 Utf8StrFmt("%Rrc", vrc).c_str()); 685 739 } 686 740 … … 703 757 va_list va; 704 758 va_start(va, pcszMsgFmt); 705 hrc = setErrorInternal (hrc,706 this->getClassIID(),707 this->getComponentName(),708 Utf8Str(pcszMsgFmt, va),709 false /* aWarning */,710 true /* aLogIt */,711 vrc /* aResultDetail */);759 hrc = setErrorInternalV(hrc, 760 this->getClassIID(), 761 this->getComponentName(), 762 pcszMsgFmt, va, 763 false /* aWarning */, 764 true /* aLogIt */, 765 vrc /* aResultDetail */); 712 766 va_end(va); 713 767 return hrc; … … 724 778 va_list args; 725 779 va_start(args, pcsz); 726 HRESULT rc = setErrorInternal (aResultCode,727 this->getClassIID(),728 this->getComponentName(),729 Utf8Str(pcsz, args),730 true /* aWarning */,731 true /* aLogIt */);780 HRESULT rc = setErrorInternalV(aResultCode, 781 this->getClassIID(), 782 this->getComponentName(), 783 pcsz, args, 784 true /* aWarning */, 785 true /* aLogIt */); 732 786 va_end(args); 733 787 return rc; … … 744 798 va_list args; 745 799 va_start(args, pcsz); 746 HRESULT rc = setErrorInternal (aResultCode,747 this->getClassIID(),748 this->getComponentName(),749 Utf8Str(pcsz, args),750 false /* aWarning */,751 false /* aLogIt */);800 HRESULT rc = setErrorInternalV(aResultCode, 801 this->getClassIID(), 802 this->getComponentName(), 803 pcsz, args, 804 false /* aWarning */, 805 false /* aLogIt */); 752 806 va_end(args); 753 807 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.