VirtualBox

Changeset 51770 in vbox for trunk/src/VBox/Runtime/common


Ignore:
Timestamp:
Jul 1, 2014 6:14:02 PM (11 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
94611
Message:

Merged in iprt++ dev branch.

Location:
trunk
Files:
108 added
1 deleted
21 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/VBox

  • trunk/src/VBox/Runtime/common/err/errinfo.cpp

    r44529 r51770  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Error Info.
     3 * IPRT - Error Info, Setters.
    44 */
    55
    66/*
    7  * Copyright (C) 2010-2012 Oracle Corporation
     7 * Copyright (C) 2010-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3333
    3434#include <iprt/assert.h>
    35 #include <iprt/mem.h>
    3635#include <iprt/string.h>
    3736
    3837
    39 
    40 RTDECL(PRTERRINFO)  RTErrInfoAlloc(size_t cbMsg)
    41 {
    42     PRTERRINFO pErrInfo;
    43     RTErrInfoAllocEx(cbMsg, &pErrInfo);
    44     return pErrInfo;
    45 }
    46 
    47 
    48 RTDECL(int)         RTErrInfoAllocEx(size_t cbMsg, PRTERRINFO *ppErrInfo)
    49 {
    50     if (cbMsg == 0)
    51         cbMsg = _4K;
    52     else
    53         cbMsg = RT_ALIGN_Z(cbMsg, 256);
    54 
    55     PRTERRINFO pErrInfo;
    56     *ppErrInfo = pErrInfo = (PRTERRINFO)RTMemTmpAlloc(sizeof(*pErrInfo) + cbMsg);
    57     if (RT_UNLIKELY(!pErrInfo))
    58         return VERR_NO_TMP_MEMORY;
    59 
    60     RTErrInfoInit(pErrInfo, (char *)(pErrInfo + 1), cbMsg);
    61     pErrInfo->fFlags = RTERRINFO_FLAGS_T_ALLOC | RTERRINFO_FLAGS_MAGIC;
    62     return VINF_SUCCESS;
    63 }
    64 
    65 
    66 RTDECL(void)        RTErrInfoFree(PRTERRINFO pErrInfo)
    67 {
    68     RTMemTmpFree(pErrInfo);
    69 }
    70 
    71 
    72 RTDECL(int)         RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg)
     38RTDECL(int) RTErrInfoSet(PRTERRINFO pErrInfo, int rc, const char *pszMsg)
    7339{
    7440    if (pErrInfo)
     
    8551
    8652
    87 RTDECL(int)         RTErrInfoSetF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...)
     53RTDECL(int) RTErrInfoSetF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...)
    8854{
    8955    va_list va;
     
    9561
    9662
    97 RTDECL(int)         RTErrInfoSetV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va)
     63RTDECL(int) RTErrInfoSetV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va)
    9864{
    9965    if (pErrInfo)
     
    10975}
    11076
     77
     78RTDECL(int) RTErrInfoAdd(PRTERRINFO pErrInfo, int rc, const char *pszMsg)
     79{
     80    if (pErrInfo)
     81    {
     82        AssertPtr(pErrInfo);
     83        if (pErrInfo->fFlags & RTERRINFO_FLAGS_SET)
     84            RTStrCat(pErrInfo->pszMsg, pErrInfo->cbMsg, pszMsg);
     85        else
     86        {
     87            while (*pszMsg == ' ')
     88                pszMsg++;
     89            return RTErrInfoSet(pErrInfo, rc, pszMsg);
     90        }
     91    }
     92    return rc;
     93}
     94
     95
     96RTDECL(int) RTErrInfoAddF(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...)
     97{
     98    va_list va;
     99    va_start(va, pszFormat);
     100    RTErrInfoAddV(pErrInfo, rc, pszFormat, va);
     101    va_end(va);
     102    return rc;
     103}
     104
     105
     106RTDECL(int) RTErrInfoAddV(PRTERRINFO pErrInfo, int rc, const char *pszFormat, va_list va)
     107{
     108    if (pErrInfo)
     109    {
     110        AssertPtr(pErrInfo);
     111        Assert((pErrInfo->fFlags & RTERRINFO_FLAGS_MAGIC_MASK) == RTERRINFO_FLAGS_MAGIC);
     112        if (pErrInfo->fFlags & RTERRINFO_FLAGS_SET)
     113        {
     114            char *pszOut = (char *)memchr(pErrInfo->pszMsg, '\0', pErrInfo->cbMsg - 2);
     115            if (pszOut)
     116                RTStrPrintfV(pszOut, &pErrInfo->pszMsg[pErrInfo->cbMsg] - pszOut, pszFormat, va);
     117        }
     118        else
     119        {
     120            while (*pszFormat == ' ')
     121                pszFormat++;
     122            return RTErrInfoSetV(pErrInfo, rc, pszFormat, va);
     123        }
     124    }
     125    return rc;
     126}
     127
  • trunk/src/VBox/Runtime/common/err/errmsg.cpp

    r48935 r51770  
    4646static const RTSTATUSMSG  g_aStatusMsgs[] =
    4747{
    48 #include "errmsgdata.h"
     48#ifndef IPRT_NO_ERROR_DATA
     49# include "errmsgdata.h"
     50#else
     51    { "Success.", "Success.", "VINF_SUCCESS", 0 },
     52#endif
    4953    { NULL, NULL, NULL, 0 }
    5054};
     
    7781    unsigned iFound = ~0;
    7882    unsigned i;
    79     for (i = 0; i < RT_ELEMENTS(g_aStatusMsgs); i++)
     83    for (i = 0; i < RT_ELEMENTS(g_aStatusMsgs) - 1; i++)
    8084    {
    8185        if (g_aStatusMsgs[i].iCode == rc)
     
    105109     */
    106110    int iMsg = ASMAtomicXchgU32(&g_iUnknownMsgs, (g_iUnknownMsgs + 1) % RT_ELEMENTS(g_aUnknownMsgs));
    107     RTStrPrintf(&g_aszUnknownStr[iMsg][0], sizeof(g_aszUnknownStr[iMsg]), "Unknown Status 0x%X", rc);
     111    RTStrPrintf(&g_aszUnknownStr[iMsg][0], sizeof(g_aszUnknownStr[iMsg]), "Unknown Status %d (%#x)", rc, rc);
    108112    return &g_aUnknownMsgs[iMsg];
    109113}
  • trunk/src/VBox/Runtime/common/ldr/Makefile.kup

    r5430 r51770  
     1
  • trunk/src/VBox/Runtime/common/ldr/ldr.cpp

    r49044 r51770  
    3939#include <iprt/log.h>
    4040#include "internal/ldr.h"
    41 
    42 
    43 RTDECL(bool) RTLdrIsLoadable(const char *pszFilename)
    44 {
    45     /*
    46      * Try to load the library.
    47      */
    48     RTLDRMOD hLib;
    49     int rc = RTLdrLoad(pszFilename, &hLib);
    50     if (RT_SUCCESS(rc))
    51     {
    52         RTLdrClose(hLib);
    53         return true;
    54     }
    55     return false;
    56 }
    57 RT_EXPORT_SYMBOL(RTLdrIsLoadable);
    5841
    5942
  • trunk/src/VBox/Runtime/common/ldr/ldrELF.cpp

    r48935 r51770  
    117117 * @param   enmArch     Architecture specifier.
    118118 * @param   phLdrMod    Where to store the handle.
     119 * @param   pErrInfo    Where to return extended error information. Optional.
    119120 */
    120 int rtldrELFOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod)
     121int rtldrELFOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
    121122{
    122123    const char *pszLogName = pReader->pfnLogName(pReader); NOREF(pszLogName);
  • trunk/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h

    r49044 r51770  
    14021402    RTLDRELF_NAME(ReadDbgInfo),
    14031403    NULL /*pfnQueryProp*/,
     1404    NULL /*pfnVerifySignature*/,
     1405    NULL /*pfnHashImage*/,
    14041406    42
    14051407};
  • trunk/src/VBox/Runtime/common/ldr/ldrEx.cpp

    r49044 r51770  
    3333#include "internal/iprt.h"
    3434
    35 #include <iprt/alloc.h>
    3635#include <iprt/assert.h>
     36#include <iprt/err.h>
    3737#include <iprt/log.h>
     38#include <iprt/md5.h>
     39#include <iprt/mem.h>
     40#include <iprt/sha.h>
    3841#include <iprt/string.h>
    39 #include <iprt/err.h>
    4042#include "internal/ldr.h"
    4143#include "internal/ldrMZ.h"
    4244
    43 
    44 /**
    45  * Open part with reader.
    46  *
    47  * @returns iprt status code.
    48  * @param   pReader     The loader reader instance which will provide the raw image bits.
    49  * @param   fFlags      Reserved, MBZ.
    50  * @param   enmArch     Architecture specifier.
    51  * @param   phMod       Where to store the handle.
    52  */
    53 int rtldrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phMod)
    54 {
     45#ifdef LDR_ONLY_PE
     46# undef LDR_WITH_PE
     47# undef LDR_WITH_KLDR
     48# undef LDR_WITH_ELF
     49# undef LDR_WITH_LX
     50# undef LDR_WITH_LE
     51# undef LDR_WITH_NE
     52# undef LDR_WITH_MZ
     53# undef LDR_WITH_AOUT
     54# define LDR_WITH_PE
     55#endif
     56
     57
     58RTDECL(int) RTLdrOpenWithReader(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phMod, PRTERRINFO pErrInfo)
     59{
     60    /*
     61     * Resolve RTLDRARCH_HOST.
     62     */
     63    if (enmArch == RTLDRARCH_HOST)
     64#if   defined(RT_ARCH_AMD64)
     65        enmArch = RTLDRARCH_AMD64;
     66#elif defined(RT_ARCH_X86)
     67        enmArch = RTLDRARCH_X86_32;
     68#else
     69        enmArch = RTLDRARCH_WHATEVER;
     70#endif
     71
    5572    /*
    5673     * Read and verify the file signature.
     
    105122    if (uSign.u32 == IMAGE_NT_SIGNATURE)
    106123#ifdef LDR_WITH_PE
    107         rc = rtldrPEOpen(pReader, fFlags, enmArch, offHdr, phMod);
     124        rc = rtldrPEOpen(pReader, fFlags, enmArch, offHdr, phMod, pErrInfo);
    108125#else
    109126        rc = VERR_PE_EXE_NOT_SUPPORTED;
     
    111128    else if (uSign.u32 == IMAGE_ELF_SIGNATURE)
    112129#if defined(LDR_WITH_ELF)
    113         rc = rtldrELFOpen(pReader, fFlags, enmArch, phMod);
     130        rc = rtldrELFOpen(pReader, fFlags, enmArch, phMod, pErrInfo);
    114131#else
    115132        rc = VERR_ELF_EXE_NOT_SUPPORTED;
     
    117134    else if (uSign.au16[0] == IMAGE_LX_SIGNATURE)
    118135#ifdef LDR_WITH_LX
    119         rc = rtldrLXOpen(pReader, fFlags, enmArch, offHdr, phMod);
     136        rc = rtldrLXOpen(pReader, fFlags, enmArch, offHdr, phMod, pErrInfo);
    120137#else
    121138        rc = VERR_LX_EXE_NOT_SUPPORTED;
     
    123140    else if (uSign.au16[0] == IMAGE_LE_SIGNATURE)
    124141#ifdef LDR_WITH_LE
    125         rc = rtldrLEOpen(pReader, fFlags, enmArch, phMod);
     142        rc = rtldrLEOpen(pReader, fFlags, enmArch, phMod, pErrInfo);
    126143#else
    127144        rc = VERR_LE_EXE_NOT_SUPPORTED;
     
    129146    else if (uSign.au16[0] == IMAGE_NE_SIGNATURE)
    130147#ifdef LDR_WITH_NE
    131         rc = rtldrNEOpen(pReader, fFlags, enmArch, phMod);
     148        rc = rtldrNEOpen(pReader, fFlags, enmArch, phMod, pErrInfo);
    132149#else
    133150        rc = VERR_NE_EXE_NOT_SUPPORTED;
     
    135152    else if (uSign.au16[0] == IMAGE_DOS_SIGNATURE)
    136153#ifdef LDR_WITH_MZ
    137         rc = rtldrMZOpen(pReader, fFlags, enmArch, phMod);
     154        rc = rtldrMZOpen(pReader, fFlags, enmArch, phMod, pErrInfo);
    138155#else
    139156        rc = VERR_MZ_EXE_NOT_SUPPORTED;
     
    143160             0)
    144161#ifdef LDR_WITH_AOUT
    145         rc = rtldrAOUTOpen(pReader, fFlags, enmArch, phMod);
     162        rc = rtldrAOUTOpen(pReader, fFlags, enmArch, phMod, pErrInfo);
    146163#else
    147164        rc = VERR_AOUT_EXE_NOT_SUPPORTED;
     
    158175    /* Try kLdr if it's a format we don't recognize. */
    159176    if (rc <= VERR_INVALID_EXE_SIGNATURE && rc > VERR_BAD_EXE_FORMAT)
    160         rc = rtldrkLdrOpen(pReader, fFlags, enmArch, phMod);
     177    {
     178        int rc2 = rtldrkLdrOpen(pReader, fFlags, enmArch, phMod, pErrInfo);
     179        if (rc2 == VERR_MZ_EXE_NOT_SUPPORTED) /* Quick fix for bad return code. */
     180            rc = rc;
     181    }
    161182#endif
    162183
     
    542563RTDECL(int) RTLdrQueryProp(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf)
    543564{
     565    return RTLdrQueryPropEx(hLdrMod, enmProp, pvBuf, cbBuf, NULL);
     566}
     567RT_EXPORT_SYMBOL(RTLdrQueryProp);
     568
     569
     570RTDECL(int) RTLdrQueryPropEx(RTLDRMOD hLdrMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet)
     571{
    544572    AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), RTLDRENDIAN_INVALID);
    545573    PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
    546574
     575    AssertPtrNullReturn(pcbRet, VERR_INVALID_POINTER);
     576    size_t cbRet;
     577    if (!pcbRet)
     578        pcbRet = &cbRet;
     579
    547580    /*
    548581     * Do some pre screening of the input
     
    551584    {
    552585        case RTLDRPROP_UUID:
     586            *pcbRet = sizeof(RTUUID);
    553587            AssertReturn(cbBuf == sizeof(RTUUID), VERR_INVALID_PARAMETER);
    554588            break;
    555589        case RTLDRPROP_TIMESTAMP_SECONDS:
     590            *pcbRet = sizeof(int64_t);
    556591            AssertReturn(cbBuf == sizeof(int32_t) || cbBuf == sizeof(int64_t), VERR_INVALID_PARAMETER);
    557592            break;
     593        case RTLDRPROP_IS_SIGNED:
     594            *pcbRet = sizeof(bool);
     595            AssertReturn(cbBuf == sizeof(bool), VERR_INVALID_PARAMETER);
     596            break;
     597        case RTLDRPROP_PKCS7_SIGNED_DATA:
     598            *pcbRet = 0;
     599            break;
     600        case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED:
     601            *pcbRet = sizeof(bool);
     602            AssertReturn(cbBuf == sizeof(bool), VERR_INVALID_PARAMETER);
     603            break;
     604
    558605        default:
    559606            AssertFailedReturn(VERR_INVALID_FUNCTION);
     
    566613    if (!pMod->pOps->pfnQueryProp)
    567614        return VERR_NOT_SUPPORTED;
    568     return pMod->pOps->pfnQueryProp(pMod, enmProp, pvBuf, cbBuf);
    569 }
    570 RT_EXPORT_SYMBOL(RTLdrQueryProp);
     615    return pMod->pOps->pfnQueryProp(pMod, enmProp, pvBuf, cbBuf, pcbRet);
     616}
     617RT_EXPORT_SYMBOL(RTLdrQueryPropEx);
     618
     619
     620RTDECL(int) RTLdrVerifySignature(RTLDRMOD hLdrMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser, PRTERRINFO pErrInfo)
     621{
     622    AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), VERR_INVALID_HANDLE);
     623    PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
     624    AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
     625
     626    /*
     627     * Call the image specific worker, if there is one.
     628     */
     629    if (!pMod->pOps->pfnVerifySignature)
     630        return VERR_NOT_SUPPORTED;
     631    return pMod->pOps->pfnVerifySignature(pMod, pfnCallback, pvUser, pErrInfo);
     632}
     633RT_EXPORT_SYMBOL(RTLdrVerifySignature);
     634
     635
     636RTDECL(int) RTLdrHashImage(RTLDRMOD hLdrMod, RTDIGESTTYPE enmDigest, char *pszDigest, size_t cbDigest)
     637{
     638    AssertMsgReturn(rtldrIsValid(hLdrMod), ("hLdrMod=%p\n", hLdrMod), VERR_INVALID_HANDLE);
     639    PRTLDRMODINTERNAL pMod = (PRTLDRMODINTERNAL)hLdrMod;
     640
     641    /*
     642     * Make sure there is sufficient space for the wanted digest and that
     643     * it's supported.
     644     */
     645    switch (enmDigest)
     646    {
     647        case RTDIGESTTYPE_MD5:      AssertReturn(cbDigest >= RTMD5_DIGEST_LEN    + 1, VERR_BUFFER_OVERFLOW); break;
     648        case RTDIGESTTYPE_SHA1:     AssertReturn(cbDigest >= RTSHA1_DIGEST_LEN   + 1, VERR_BUFFER_OVERFLOW); break;
     649        case RTDIGESTTYPE_SHA256:   AssertReturn(cbDigest >= RTSHA256_DIGEST_LEN + 1, VERR_BUFFER_OVERFLOW); break;
     650        case RTDIGESTTYPE_SHA512:   AssertReturn(cbDigest >= RTSHA512_DIGEST_LEN + 1, VERR_BUFFER_OVERFLOW); break;
     651        default:
     652            if (enmDigest > RTDIGESTTYPE_INVALID && enmDigest < RTDIGESTTYPE_END)
     653                return VERR_NOT_SUPPORTED;
     654            AssertFailedReturn(VERR_INVALID_PARAMETER);
     655    }
     656    AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
     657
     658    /*
     659     * Call the image specific worker, if there is one.
     660     */
     661    if (!pMod->pOps->pfnHashImage)
     662        return VERR_NOT_SUPPORTED;
     663    return pMod->pOps->pfnHashImage(pMod, enmDigest, pszDigest, cbDigest);
     664}
     665RT_EXPORT_SYMBOL(RTLdrHashImage);
    571666
    572667
  • trunk/src/VBox/Runtime/common/ldr/ldrFile.cpp

    r48935 r51770  
    218218            if (RT_SUCCESS(rc))
    219219            {
     220                pFileReader->Core.uMagic     = RTLDRREADER_MAGIC;
    220221                pFileReader->Core.pfnRead    = rtldrFileRead;
    221222                pFileReader->Core.pfnTell    = rtldrFileTell;
     
    258259
    259260    /*
    260      * Resolve RTLDRARCH_HOST.
    261      */
    262     if (enmArch == RTLDRARCH_HOST)
    263 #if   defined(RT_ARCH_AMD64)
    264         enmArch = RTLDRARCH_AMD64;
    265 #elif defined(RT_ARCH_X86)
    266         enmArch = RTLDRARCH_X86_32;
    267 #else
    268         enmArch = RTLDRARCH_WHATEVER;
    269 #endif
    270 
    271     /*
    272261     * Create file reader & invoke worker which identifies and calls the image interpreter.
    273262     */
     
    276265    if (RT_SUCCESS(rc))
    277266    {
    278         rc = rtldrOpenWithReader(pReader, fFlags, enmArch, phLdrMod);
     267        rc = RTLdrOpenWithReader(pReader, fFlags, enmArch, phLdrMod, NULL);
    279268        if (RT_SUCCESS(rc))
    280269        {
     
    309298
    310299    /*
    311      * Resolve RTLDRARCH_HOST.
    312      */
    313     if (enmArch == RTLDRARCH_HOST)
    314 # if   defined(RT_ARCH_AMD64)
    315         enmArch = RTLDRARCH_AMD64;
    316 # elif defined(RT_ARCH_X86)
    317         enmArch = RTLDRARCH_X86_32;
    318 # else
    319         enmArch = RTLDRARCH_WHATEVER;
    320 # endif
    321 
    322     /*
    323300     * Create file reader & invoke worker which identifies and calls the image interpreter.
    324301     */
     
    327304    if (RT_SUCCESS(rc))
    328305    {
    329         rc = rtldrkLdrOpen(pReader, fFlags, enmArch, phLdrMod);
     306        rc = rtldrkLdrOpen(pReader, fFlags, enmArch, phLdrMod, NULL);
    330307        if (RT_SUCCESS(rc))
    331308        {
  • trunk/src/VBox/Runtime/common/ldr/ldrMemory.cpp

    r51519 r51770  
    244244        pThis->pvMapping    = NULL;
    245245        pThis->cMappings    = 0;
    246         pThis->Core.pszName    = "rdrmem";
     246        pThis->Core.uMagic     = RTLDRREADER_MAGIC;
    247247        pThis->Core.pfnRead    = rtldrRdrMem_Read;
    248248        pThis->Core.pfnTell    = rtldrRdrMem_Tell;
     
    305305    if (RT_SUCCESS(rc))
    306306    {
    307         rc = rtldrOpenWithReader(pReader, fFlags, enmArch, phLdrMod);
     307        rc = RTLdrOpenWithReader(pReader, fFlags, enmArch, phLdrMod, NULL);
    308308        if (RT_SUCCESS(rc))
    309309        {
  • trunk/src/VBox/Runtime/common/ldr/ldrNative.cpp

    r49044 r51770  
    7171    rtldrNativeEnumSymbols,
    7272    /* ext: */
     73    NULL,
     74    NULL,
    7375    NULL,
    7476    NULL,
     
    319321RT_EXPORT_SYMBOL(RTLdrGetNativeHandle);
    320322
     323
     324RTDECL(bool) RTLdrIsLoadable(const char *pszFilename)
     325{
     326    /*
     327     * Try to load the library.
     328     */
     329    RTLDRMOD hLib;
     330    int rc = RTLdrLoad(pszFilename, &hLib);
     331    if (RT_SUCCESS(rc))
     332    {
     333        RTLdrClose(hLib);
     334        return true;
     335    }
     336    return false;
     337}
     338RT_EXPORT_SYMBOL(RTLdrIsLoadable);
     339
  • trunk/src/VBox/Runtime/common/ldr/ldrPE.cpp

    r49044 r51770  
    3333#include "internal/iprt.h"
    3434
    35 #include <iprt/alloc.h>
    3635#include <iprt/assert.h>
     36#include <iprt/asm.h>
     37#include <iprt/err.h>
    3738#include <iprt/log.h>
     39#include <iprt/md5.h>
     40#include <iprt/mem.h>
    3841#include <iprt/path.h>
     42#include <iprt/sha.h>
    3943#include <iprt/string.h>
    40 #include <iprt/err.h>
     44#ifndef IPRT_WITHOUT_LDR_VERIFY
     45# include <iprt/crypto/pkcs7.h>
     46# include <iprt/crypto/spc.h>
     47# include <iprt/crypto/x509.h>
     48#endif
    4149#include <iprt/formats/codeview.h>
    4250#include "internal/ldrPE.h"
     
    5361 */
    5462#define PE_RVA2TYPE(pvBits, rva, type)  ((type) ((uintptr_t)pvBits + (uintptr_t)(rva)) )
     63
     64/** The max size of the security directory. */
     65#ifdef IN_RING3
     66# define RTLDRMODPE_MAX_SECURITY_DIR_SIZE   _4M
     67#else
     68# define RTLDRMODPE_MAX_SECURITY_DIR_SIZE   _1M
     69#endif
    5570
    5671
     
    92107    /** The image timestamp. */
    93108    uint32_t                uTimestamp;
     109    /** Set if the image is 64-bit, clear if 32-bit. */
     110    bool                    f64Bit;
    94111    /** The import data directory entry. */
    95112    IMAGE_DATA_DIRECTORY    ImportDir;
     
    100117    /** The debug directory entry. */
    101118    IMAGE_DATA_DIRECTORY    DebugDir;
    102 } RTLDRMODPE, *PRTLDRMODPE;
     119    /** The security directory entry. */
     120    IMAGE_DATA_DIRECTORY    SecurityDir;
     121
     122    /** Offset of the first PKCS \#7 SignedData signature if present. */
     123    uint32_t                offPkcs7SignedData;
     124    /** Size of the first PKCS \#7 SignedData. */
     125    uint32_t                cbPkcs7SignedData;
     126
     127    /** Copy of the optional header field DllCharacteristics. */
     128    uint16_t                fDllCharacteristics;
     129} RTLDRMODPE;
     130/** Pointer to the instance data for a PE loader module. */
     131typedef RTLDRMODPE *PRTLDRMODPE;
     132
    103133
    104134/**
     
    132162
    133163
     164/**
     165 * PE hash context union.
     166 */
     167typedef union RTLDRPEHASHCTXUNION
     168{
     169    RTSHA512CONTEXT Sha512;
     170    RTSHA256CONTEXT Sha256;
     171    RTSHA1CONTEXT   Sha1;
     172    RTMD5CONTEXT    Md5;
     173} RTLDRPEHASHCTXUNION;
     174/** Pointer to a PE hash context union. */
     175typedef RTLDRPEHASHCTXUNION *PRTLDRPEHASHCTXUNION;
     176
     177
     178/**
     179 * PE hash digests
     180 */
     181typedef union RTLDRPEHASHRESUNION
     182{
     183    uint8_t abSha512[RTSHA512_HASH_SIZE];
     184    uint8_t abSha256[RTSHA256_HASH_SIZE];
     185    uint8_t abSha1[RTSHA1_HASH_SIZE];
     186    uint8_t abMd5[RTMD5_HASH_SIZE];
     187} RTLDRPEHASHRESUNION;
     188/** Pointer to a PE hash work set. */
     189typedef RTLDRPEHASHRESUNION *PRTLDRPEHASHRESUNION;
     190
     191/**
     192 * Special places to watch out for when hashing a PE image.
     193 */
     194typedef struct RTLDRPEHASHSPECIALS
     195{
     196    uint32_t    cbToHash;
     197    uint32_t    offCksum;
     198    uint32_t    cbCksum;
     199    uint32_t    offSecDir;
     200    uint32_t    cbSecDir;
     201    uint32_t    offEndSpecial;
     202} RTLDRPEHASHSPECIALS;
     203/** Pointer to the structure with the special hash places. */
     204typedef RTLDRPEHASHSPECIALS *PRTLDRPEHASHSPECIALS;
     205
     206
     207#ifndef IPRT_WITHOUT_LDR_VERIFY
     208/**
     209 * Parsed signature data.
     210 */
     211typedef struct RTLDRPESIGNATURE
     212{
     213    /** The outer content info wrapper. */
     214    RTCRPKCS7CONTENTINFO        ContentInfo;
     215    /** Pointer to the decoded SignedData inside the ContentInfo member. */
     216    PRTCRPKCS7SIGNEDDATA        pSignedData;
     217    /** Pointer to the indirect data content. */
     218    PRTCRSPCINDIRECTDATACONTENT pIndData;
     219    /** The digest type employed by the signature. */
     220    RTDIGESTTYPE                enmDigest;
     221
     222    /** Pointer to the raw signatures.  This is allocated in the continuation of
     223     * this structure to keep things simple.  The size is given by  the security
     224     * export directory. */
     225    WIN_CERTIFICATE const      *pRawData;
     226
     227    /** Hash scratch data. */
     228    RTLDRPEHASHCTXUNION         HashCtx;
     229    /** Hash result. */
     230    RTLDRPEHASHRESUNION         HashRes;
     231} RTLDRPESIGNATURE;
     232/** Pointed to SigneData parsing stat and output. */
     233typedef RTLDRPESIGNATURE *PRTLDRPESIGNATURE;
     234#endif
     235
     236
    134237/*******************************************************************************
    135238*   Internal Functions                                                         *
     
    251354        {
    252355            if ((RTFOFF)offFile + cbToRead > cbFile)
    253                 cbToRead = cbFile - (RTFOFF)offFile;
     356                cbToRead = (uint32_t)(cbFile - (RTFOFF)offFile);
    254357            int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbToRead, offFile);
    255358            if (RT_FAILURE(rc))
     
    331434    if (uRva == NIL_RTLDRADDR || uRva > pThis->cbImage)
    332435    {
    333         if (offFile < 0)
     436        if (offFile < 0 || offFile >= UINT32_MAX)
    334437            return VERR_INVALID_PARAMETER;
    335         return rtldrPEReadPartFromFile(pThis, offFile, cbMem, ppvMem);
    336     }
    337     return rtldrPEReadPartByRva(pThis, pvBits, uRva, cbMem, ppvMem);
     438        return rtldrPEReadPartFromFile(pThis, (uint32_t)offFile, cbMem, ppvMem);
     439    }
     440    return rtldrPEReadPartByRva(pThis, pvBits, (uint32_t)uRva, cbMem, ppvMem);
    338441}
    339442
     
    549652                rc = VERR_BAD_EXE_FORMAT;
    550653            }
    551             pFirstThunk->u1.Function = Value;
     654            pFirstThunk->u1.Function = (uint32_t)Value;
    552655            if (pFirstThunk->u1.Function != Value)
    553656            {
     
    664767        /* Some bound checking just to be sure it works... */
    665768        if ((uintptr_t)pbr - (uintptr_t)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs)
    666             cRelocations = (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
     769            cRelocations = (uint32_t)(  (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION))
     770                                      / sizeof(uint16_t) );
    667771
    668772        /*
     
    692796            {
    693797                case IMAGE_REL_BASED_HIGHLOW:   /* 32-bit, add delta. */
    694                     *u.pu32 += uDelta;
     798                    *u.pu32 += (uint32_t)uDelta;
    695799                    break;
    696800                case IMAGE_REL_BASED_DIR64:     /* 64-bit, add delta. */
     
    717821                    pwoffFixup++;
    718822                    int32_t i32 = (uint32_t)(*u.pu16 << 16) | *pwoffFixup;
    719                     i32 += uDelta;
     823                    i32 += (uint32_t)uDelta;
    720824                    i32 += 0x8000; //??
    721825                    *u.pu16 = (uint16_t)(i32 >> 16);
     
    760864
    761865/** @copydoc RTLDROPS::pfnRelocate. */
    762 static int rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
     866static DECLCALLBACK(int) rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress,
     867                                         PFNRTLDRIMPORT pfnGetImport, void *pvUser)
    763868{
    764869    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     
    9261031    if (RT_SUCCESS(rc))
    9271032    {
    928         uintptr_t  uNamePrev = 0;
     1033        uint32_t uNamePrev = 0;
    9291034        for (uint32_t uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
    9301035        {
     
    10631168    uint32_t   *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
    10641169    uint16_t   *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
    1065     uintptr_t   uNamePrev = 0;
     1170    uint32_t    uNamePrev = 0;
    10661171    unsigned    cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
    10671172    for (unsigned uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
     
    10741179            const char *pszName = NULL;
    10751180            /* Search from previous + 1 to the end.  */
    1076             unsigned    uName = uNamePrev + 1;
     1181            uint32_t uName = uNamePrev + 1;
    10771182            while (uName < pExpDir->NumberOfNames)
    10781183            {
     
    11471252
    11481253    /*
     1254     * Allocate temporary memory for a path buffer (this code is also compiled
     1255     * and maybe even used in stack starved environments).
     1256     */
     1257    char *pszPath = (char *)RTMemTmpAlloc(RTPATH_MAX);
     1258    if (!pszPath)
     1259        return VERR_NO_TMP_MEMORY;
     1260
     1261    /*
    11491262     * Get the debug directory.
    11501263     */
     
    11561269                                     (void const **)&paDbgDir);
    11571270    if (RT_FAILURE(rcRet))
     1271    {
     1272        RTMemTmpFree(pszPath);
    11581273        return rcRet;
     1274    }
    11591275
    11601276    /*
     
    11701286
    11711287        void const     *pvPart = NULL;
    1172         char            szPath[RTPATH_MAX];
    11731288        RTLDRDBGINFO    DbgInfo;
    11741289        RT_ZERO(DbgInfo.u);
     
    11901305                DbgInfo.u.Cv.uMinorVer  = paDbgDir[i].MinorVersion;
    11911306                DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
    1192                 if (   paDbgDir[i].SizeOfData < sizeof(szPath)
     1307                if (   paDbgDir[i].SizeOfData < RTPATH_MAX
    11931308                    && paDbgDir[i].SizeOfData > 16
    11941309                    && (   DbgInfo.LinkAddress != NIL_RTLDRADDR
     
    12281343            case IMAGE_DEBUG_TYPE_MISC:
    12291344                DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
    1230                 if (   paDbgDir[i].SizeOfData < sizeof(szPath)
     1345                if (   paDbgDir[i].SizeOfData < RTPATH_MAX
    12311346                    && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
    12321347                {
     
    12491364                            else
    12501365                            {
    1251                                 char *pszPath = szPath;
    12521366                                rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
    12531367                                                     (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
    1254                                                      &pszPath, sizeof(szPath), NULL);
     1368                                                     &pszPath, RTPATH_MAX, NULL);
    12551369                                if (RT_SUCCESS(rc))
    1256                                     DbgInfo.pszExtFile = szPath;
     1370                                    DbgInfo.pszExtFile = pszPath;
    12571371                                else
    12581372                                    rcRet = rc; /* continue without a filename. */
     
    12831397           it's probably the current ANSI/Windows code page for the process
    12841398           generating the image anyways.) */
    1285         if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath)
    1286         {
    1287             char *pszPath = szPath;
     1399        if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != pszPath)
     1400        {
    12881401            rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
    12891402                                  paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
    1290                                   &pszPath, sizeof(szPath), NULL);
     1403                                  &pszPath, RTPATH_MAX, NULL);
    12911404            if (RT_FAILURE(rc))
    12921405            {
     
    12961409        }
    12971410        if (DbgInfo.pszExtFile)
    1298             RTPathChangeToUnixSlashes(szPath, true /*fForce*/);
     1411            RTPathChangeToUnixSlashes(pszPath, true /*fForce*/);
    12991412
    13001413        rc = pfnCallback(pMod, &DbgInfo, pvUser);
     
    13081421
    13091422    rtldrPEFreePart(pModPe, pvBits, paDbgDir);
     1423    RTMemTmpFree(pszPath);
    13101424    return rcRet;
    13111425}
     
    14911605
    14921606/** @interface_method_impl{RTLDROPS,pfnQueryProp} */
    1493 static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf)
     1607static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet)
    14941608{
    14951609    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     
    14971611    {
    14981612        case RTLDRPROP_TIMESTAMP_SECONDS:
     1613            Assert(*pcbRet == cbBuf);
    14991614            if (cbBuf == sizeof(int32_t))
    15001615                *(int32_t *)pvBuf = pModPe->uTimestamp;
     
    15021617                *(int64_t *)pvBuf = pModPe->uTimestamp;
    15031618            else
    1504                 return VERR_INVALID_PARAMETER;
     1619                AssertFailedReturn(VERR_INTERNAL_ERROR_3);
     1620            break;
     1621
     1622        case RTLDRPROP_IS_SIGNED:
     1623            Assert(cbBuf == sizeof(bool));
     1624            Assert(*pcbRet == cbBuf);
     1625            *(bool *)pvBuf = pModPe->offPkcs7SignedData != 0;
     1626            break;
     1627
     1628        case RTLDRPROP_PKCS7_SIGNED_DATA:
     1629        {
     1630            if (pModPe->cbPkcs7SignedData == 0)
     1631                return VERR_NOT_FOUND;
     1632            Assert(pModPe->offPkcs7SignedData > pModPe->SecurityDir.VirtualAddress);
     1633
     1634            *pcbRet = pModPe->cbPkcs7SignedData;
     1635            if (cbBuf < pModPe->cbPkcs7SignedData)
     1636                return VERR_BUFFER_OVERFLOW;
     1637            return pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pvBuf, pModPe->cbPkcs7SignedData,
     1638                                                 pModPe->offPkcs7SignedData);
     1639        }
     1640
     1641        case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED:
     1642            Assert(cbBuf == sizeof(bool));
     1643            Assert(*pcbRet == cbBuf);
     1644            *(bool *)pvBuf = pModPe->offPkcs7SignedData > 0
     1645                          && (pModPe->fDllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY);
    15051646            break;
    15061647
     
    15121653
    15131654
     1655
     1656/*
     1657 * Lots of Authenticode fun ahead.
     1658 */
     1659
     1660
     1661/**
     1662 * Initializes the hash context.
     1663 *
     1664 * @returns VINF_SUCCESS or VERR_NOT_SUPPORTED.
     1665 * @param   pHashCtx            The hash context union.
     1666 * @param   enmDigest           The hash type we're calculating..
     1667 */
     1668static int rtLdrPE_HashInit(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest)
     1669{
     1670    switch (enmDigest)
     1671    {
     1672        case RTDIGESTTYPE_SHA512:  RTSha512Init(&pHashCtx->Sha512); break;
     1673        case RTDIGESTTYPE_SHA256:  RTSha256Init(&pHashCtx->Sha256); break;
     1674        case RTDIGESTTYPE_SHA1:    RTSha1Init(&pHashCtx->Sha1); break;
     1675        case RTDIGESTTYPE_MD5:     RTMd5Init(&pHashCtx->Md5); break;
     1676        default:                   AssertFailedReturn(VERR_NOT_SUPPORTED);
     1677    }
     1678    return VINF_SUCCESS;
     1679}
     1680
     1681
     1682/**
     1683 * Updates the hash with more data.
     1684 *
     1685 * @param   pHashCtx            The hash context union.
     1686 * @param   enmDigest           The hash type we're calculating..
     1687 * @param   pvBuf               Pointer to a buffer with bytes to add to thash.
     1688 * @param   cbBuf               How many bytes to add from @a pvBuf.
     1689 */
     1690static void rtLdrPE_HashUpdate(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, void const *pvBuf, size_t cbBuf)
     1691{
     1692    switch (enmDigest)
     1693    {
     1694        case RTDIGESTTYPE_SHA512:  RTSha512Update(&pHashCtx->Sha512, pvBuf, cbBuf); break;
     1695        case RTDIGESTTYPE_SHA256:  RTSha256Update(&pHashCtx->Sha256, pvBuf, cbBuf); break;
     1696        case RTDIGESTTYPE_SHA1:    RTSha1Update(&pHashCtx->Sha1, pvBuf, cbBuf); break;
     1697        case RTDIGESTTYPE_MD5:     RTMd5Update(&pHashCtx->Md5, pvBuf, cbBuf); break;
     1698        default:                   AssertReleaseFailed();
     1699    }
     1700}
     1701
     1702
     1703/**
     1704 * Finalizes the hash calculations.
     1705 *
     1706 * @param   pHashCtx            The hash context union.
     1707 * @param   enmDigest           The hash type we're calculating..
     1708 * @param   pHashRes            The hash result union.
     1709 */
     1710static void rtLdrPE_HashFinalize(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, PRTLDRPEHASHRESUNION pHashRes)
     1711{
     1712    switch (enmDigest)
     1713    {
     1714        case RTDIGESTTYPE_SHA512:  RTSha512Final(&pHashCtx->Sha512, pHashRes->abSha512); break;
     1715        case RTDIGESTTYPE_SHA256:  RTSha256Final(&pHashCtx->Sha256, pHashRes->abSha256); break;
     1716        case RTDIGESTTYPE_SHA1:    RTSha1Final(&pHashCtx->Sha1, pHashRes->abSha1); break;
     1717        case RTDIGESTTYPE_MD5:     RTMd5Final(pHashRes->abMd5, &pHashCtx->Md5); break;
     1718        default:                   AssertReleaseFailed();
     1719    }
     1720}
     1721
     1722
     1723/**
     1724 * Returns the digest size for the given digest type.
     1725 *
     1726 * @returns Size in bytes.
     1727 * @param   enmDigest           The hash type in question.
     1728 */
     1729static uint32_t rtLdrPE_HashGetHashSize(RTDIGESTTYPE enmDigest)
     1730{
     1731    switch (enmDigest)
     1732    {
     1733        case RTDIGESTTYPE_SHA512:  return RTSHA512_HASH_SIZE;
     1734        case RTDIGESTTYPE_SHA256:  return RTSHA256_HASH_SIZE;
     1735        case RTDIGESTTYPE_SHA1:    return RTSHA1_HASH_SIZE;
     1736        case RTDIGESTTYPE_MD5:     return RTMD5_HASH_SIZE;
     1737        default:                   AssertReleaseFailedReturn(0);
     1738    }
     1739}
     1740
     1741
     1742/**
     1743 * Calculate the special too watch out for when hashing the image.
     1744 *
     1745 * @returns IPRT status code.
     1746 * @param   pModPe              The PE module.
     1747 * @param   pPlaces             The structure where to store the special places.
     1748 * @param   pErrInfo            Optional error info.
     1749 */
     1750static int rtldrPe_CalcSpecialHashPlaces(PRTLDRMODPE pModPe, PRTLDRPEHASHSPECIALS pPlaces, PRTERRINFO pErrInfo)
     1751{
     1752    /*
     1753     * If we're here despite a missing signature, we need to get the file size.
     1754     */
     1755    pPlaces->cbToHash = pModPe->SecurityDir.VirtualAddress;
     1756    if (pPlaces->cbToHash == 0)
     1757    {
     1758        RTFOFF cbFile = pModPe->Core.pReader->pfnSize(pModPe->Core.pReader);
     1759        pPlaces->cbToHash = (uint32_t)cbFile;
     1760        if (pPlaces->cbToHash != (RTFOFF)cbFile)
     1761            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_FILE_LENGTH_ERROR, "File is too large: %RTfoff", cbFile);
     1762    }
     1763
     1764    /*
     1765     * Calculate the special places.
     1766     */
     1767    pPlaces->offCksum       = (uint32_t)pModPe->offNtHdrs
     1768                            + (pModPe->f64Bit
     1769                               ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum)
     1770                               : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum));
     1771    pPlaces->cbCksum        = RT_SIZEOFMEMB(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
     1772    pPlaces->offSecDir      = (uint32_t)pModPe->offNtHdrs
     1773                            + (pModPe->f64Bit
     1774                               ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY])
     1775                               : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]));
     1776    pPlaces->cbSecDir       = sizeof(IMAGE_DATA_DIRECTORY);
     1777    pPlaces->offEndSpecial  = pPlaces->offSecDir + pPlaces->cbSecDir;
     1778    return VINF_SUCCESS;
     1779}
     1780
     1781
     1782/**
     1783 * Calculates the whole image hash.
     1784 *
     1785 * The Authenticode_PE.docx version 1.0 explains how the hash is calculated,
     1786 * points 8 thru 14 are bogus.  If you study them a little carefully, it is
     1787 * clear that the algorithm will only work if the raw data for the section have
     1788 * no gaps between them or in front of them.  So, this elaborate section sorting
     1789 * by PointerToRawData and working them section by section could simply be
     1790 * replaced by one point:
     1791 *
     1792 *      8. Add all the file content between SizeOfHeaders and the
     1793 *         attribute certificate table to the hash.  Then finalize
     1794 *         the hash.
     1795 *
     1796 * Not sure if Microsoft is screwing with us on purpose here or whether they
     1797 * assigned some of this work to less talented engineers and tech writers.  I
     1798 * love fact that they say it's "simplified" and should yield the correct hash
     1799 * for "almost all" files.  Stupid, Stupid, Microsofties!!
     1800 *
     1801 * My simplified implementation that just hashes the entire file up to the
     1802 * signature or end of the file produces the same SHA1 values as "signtool
     1803 * verify /v" does both for edited executables with gaps between/before/after
     1804 * sections raw data and normal executables without any gaps.
     1805 *
     1806 * @returns IPRT status code.
     1807 * @param   pModPe      The PE module.
     1808 * @param   pvScratch   Scratch buffer.
     1809 * @param   cbScratch   Size of the scratch buffer.
     1810 * @param   enmDigest   The hash digest type we're calculating.
     1811 * @param   pHashCtx    Hash context scratch area.
     1812 * @param   pHashRes    Hash result buffer.
     1813 * @param   pErrInfo    Optional error info buffer.
     1814 */
     1815static int rtldrPE_HashImageCommon(PRTLDRMODPE pModPe, void *pvScratch, uint32_t cbScratch, RTDIGESTTYPE enmDigest,
     1816                                   PRTLDRPEHASHCTXUNION pHashCtx, PRTLDRPEHASHRESUNION pHashRes, PRTERRINFO pErrInfo)
     1817{
     1818    int rc = rtLdrPE_HashInit(pHashCtx, enmDigest);
     1819    if (RT_FAILURE(rc))
     1820        return rc;
     1821
     1822    /*
     1823     * Calculate the special places.
     1824     */
     1825    RTLDRPEHASHSPECIALS SpecialPlaces;
     1826    rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo);
     1827    if (RT_FAILURE(rc))
     1828        return rc;
     1829
     1830    /*
     1831     * Work our way thru the image data.
     1832     */
     1833    uint32_t off = 0;
     1834    while (off < SpecialPlaces.cbToHash)
     1835    {
     1836        uint32_t cbRead = RT_MIN(SpecialPlaces.cbToHash - off, cbScratch);
     1837        uint8_t *pbCur  = (uint8_t *)pvScratch;
     1838        rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbRead, off);
     1839        if (RT_FAILURE(rc))
     1840            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH, "Hash read error at %#x: %Rrc (cbRead=%#zx)",
     1841                                 off, rc, cbRead);
     1842
     1843        if (off < SpecialPlaces.offEndSpecial)
     1844        {
     1845            if (off < SpecialPlaces.offCksum)
     1846            {
     1847                /* Hash everything up to the checksum. */
     1848                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbRead);
     1849                rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbChunk);
     1850                pbCur  += cbChunk;
     1851                cbRead -= cbChunk;
     1852                off    += cbChunk;
     1853            }
     1854
     1855            if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum)
     1856            {
     1857                /* Skip the checksum */
     1858                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbRead);
     1859                pbCur  += cbChunk;
     1860                cbRead -= cbChunk;
     1861                off    += cbChunk;
     1862            }
     1863
     1864            if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum)
     1865            {
     1866                /* Hash everything between the checksum and the data dir entry. */
     1867                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbRead);
     1868                rtLdrPE_HashUpdate(pHashCtx, enmDigest,  pbCur, cbChunk);
     1869                pbCur  += cbChunk;
     1870                cbRead -= cbChunk;
     1871                off    += cbChunk;
     1872            }
     1873
     1874            if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir)
     1875            {
     1876                /* Skip the security data directory entry. */
     1877                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbRead);
     1878                pbCur  += cbChunk;
     1879                cbRead -= cbChunk;
     1880                off    += cbChunk;
     1881            }
     1882        }
     1883
     1884        rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbRead);
     1885
     1886        /* Advance */
     1887        off += cbRead;
     1888    }
     1889
     1890    /*
     1891     * If there isn't a signature, experiments with signtool indicates that we
     1892     * have to zero padd the file size until it's a multiple of 8.  (This is
     1893     * most likely to give 64-bit values in the certificate a natural alignment
     1894     * when memory mapped.)
     1895     */
     1896    if (   pModPe->SecurityDir.Size != SpecialPlaces.cbToHash
     1897        && SpecialPlaces.cbToHash != RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT))
     1898    {
     1899        static const uint8_t s_abZeros[WIN_CERTIFICATE_ALIGNMENT] = { 0,0,0,0, 0,0,0,0 };
     1900        rtLdrPE_HashUpdate(pHashCtx, enmDigest, s_abZeros,
     1901                           RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT) - SpecialPlaces.cbToHash);
     1902    }
     1903
     1904    /*
     1905     * Done. Finalize the hashes.
     1906     */
     1907    rtLdrPE_HashFinalize(pHashCtx, enmDigest, pHashRes);
     1908    return VINF_SUCCESS;
     1909}
     1910
     1911#ifndef IPRT_WITHOUT_LDR_VERIFY
     1912
     1913/**
     1914 * Verifies image preconditions not checked by the open validation code.
     1915 *
     1916 * @returns IPRT status code.
     1917 * @param   pModPe              The PE module.
     1918 * @param   pErrInfo            Optional error info buffer.
     1919 */
     1920static int rtldrPE_VerifySignatureImagePrecoditions(PRTLDRMODPE pModPe, PRTERRINFO pErrInfo)
     1921{
     1922    /*
     1923     * Validate the sections.  While doing so, track the amount of section raw
     1924     * section data in the file so we can use this to validate the signature
     1925     * table location later.
     1926     */
     1927    uint32_t offNext = pModPe->cbHeaders; /* same */
     1928    for (uint32_t i = 0; i < pModPe->cSections; i++)
     1929        if (pModPe->paSections[i].SizeOfRawData > 0)
     1930        {
     1931            uint64_t offEnd = (uint64_t)pModPe->paSections[i].PointerToRawData + pModPe->paSections[i].SizeOfRawData;
     1932            if (offEnd > offNext)
     1933            {
     1934                if (offEnd >= _2G)
     1935                    return RTErrInfoSetF(pErrInfo, VERR_LDRVI_SECTION_RAW_DATA_VALUES,
     1936                                         "Section %#u specifies file data after 2GB: PointerToRawData=%#x SizeOfRawData=%#x",
     1937                                         i, pModPe->paSections[i].PointerToRawData, pModPe->paSections[i].SizeOfRawData);
     1938                offNext = (uint32_t)offEnd;
     1939            }
     1940        }
     1941    uint32_t offEndOfSectionData = offNext;
     1942
     1943    /*
     1944     * Validate the signature.
     1945     */
     1946    if (!pModPe->SecurityDir.Size)
     1947        return RTErrInfoSet(pErrInfo, VERR_LDRVI_NOT_SIGNED, "Not signed.");
     1948
     1949    uint32_t const offSignature = pModPe->SecurityDir.VirtualAddress;
     1950    uint32_t const cbSignature  = pModPe->SecurityDir.Size;
     1951    if (   cbSignature  <= sizeof(WIN_CERTIFICATE)
     1952        || cbSignature  >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE
     1953        || offSignature >= _2G)
     1954        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1955                             "Invalid security data dir entry: cb=%#x off=%#x", cbSignature, offSignature);
     1956
     1957    if (offSignature < offEndOfSectionData)
     1958        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1959                             "Invalid security data dir entry offset: %#x offEndOfSectionData=%#x",
     1960                             offSignature, offEndOfSectionData);
     1961
     1962    if (RT_ALIGN_32(offSignature, WIN_CERTIFICATE_ALIGNMENT) != offSignature)
     1963        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1964                             "Misaligned security dir entry offset: %#x (alignment=%#x)",
     1965                             offSignature, WIN_CERTIFICATE_ALIGNMENT);
     1966
     1967
     1968    return VINF_SUCCESS;
     1969}
     1970
     1971
     1972/**
     1973 * Reads and checks the raw signature data.
     1974 *
     1975 * @returns IPRT status code.
     1976 * @param   pModPe              The PE module.
     1977 * @param   ppSignature         Where to return the pointer to the parsed
     1978 *                              signature data.  Pass to
     1979 *                              rtldrPE_VerifySignatureDestroy when done.
     1980 * @param   pErrInfo            Optional error info buffer.
     1981 */
     1982static int rtldrPE_VerifySignatureRead(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE *ppSignature, PRTERRINFO pErrInfo)
     1983{
     1984    *ppSignature = NULL;
     1985    AssertReturn(pModPe->SecurityDir.Size > 0, VERR_INTERNAL_ERROR_2);
     1986
     1987    /*
     1988     * Allocate memory for reading and parsing it.
     1989     */
     1990    if (pModPe->SecurityDir.Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE)
     1991        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1992                             "Signature directory is to large: %#x", pModPe->SecurityDir.Size);
     1993
     1994    PRTLDRPESIGNATURE pSignature = (PRTLDRPESIGNATURE)RTMemTmpAllocZ(sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size);
     1995    if (!pSignature)
     1996        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_NO_MEMORY_SIGNATURE, "Failed to allocate %zu bytes",
     1997                             sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size);
     1998    pSignature->pRawData = RT_ALIGN_PT(pSignature + 1, 64, WIN_CERTIFICATE const *);
     1999
     2000
     2001    /*
     2002     * Read it.
     2003     */
     2004    int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, (void *)pSignature->pRawData,
     2005                                           pModPe->SecurityDir.Size, pModPe->SecurityDir.VirtualAddress);
     2006    if (RT_SUCCESS(rc))
     2007    {
     2008        /*
     2009         * Check the table we've read in.
     2010         */
     2011        uint32_t               cbLeft = pModPe->SecurityDir.Size;
     2012        WIN_CERTIFICATE const *pEntry = pSignature->pRawData;
     2013        for (;;)
     2014        {
     2015            if (   cbLeft           < sizeof(*pEntry)
     2016                || pEntry->dwLength > cbLeft
     2017                || pEntry->dwLength < sizeof(*pEntry))
     2018                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_LENGTH,
     2019                                   "Bad WIN_CERTIFICATE length: %#x  (max %#x, signature=%u)",
     2020                                   pEntry->dwLength, cbLeft, 0);
     2021            else if (pEntry->wRevision != WIN_CERT_REVISION_2_0)
     2022                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_REVISION,
     2023                                   "Unsupported WIN_CERTIFICATE revision value: %#x (signature=%u)",
     2024                                   pEntry->wRevision, 0);
     2025            else if (pEntry->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA)
     2026                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_TYPE,
     2027                                   "Unsupported WIN_CERTIFICATE certificate type: %#x (signature=%u)",
     2028                                   pEntry->wCertificateType, 0);
     2029            else
     2030            {
     2031                /* advance */
     2032                uint32_t cbEntry = RT_ALIGN(pEntry->dwLength, WIN_CERTIFICATE_ALIGNMENT);
     2033                if (cbEntry >= cbLeft)
     2034                    break;
     2035                cbLeft -= cbEntry;
     2036                pEntry = (WIN_CERTIFICATE *)((uintptr_t)pEntry + cbEntry);
     2037
     2038                /* For now, only one entry is supported. */
     2039                rc = RTErrInfoSet(pErrInfo, VERR_LDRVI_BAD_CERT_MULTIPLE, "Multiple WIN_CERTIFICATE entries are not supported.");
     2040            }
     2041            break;
     2042        }
     2043        if (RT_SUCCESS(rc))
     2044        {
     2045            *ppSignature = pSignature;
     2046            return VINF_SUCCESS;
     2047        }
     2048    }
     2049    else
     2050        rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_SIGNATURE, "Signature read error: %Rrc", rc);
     2051    RTMemTmpFree(pSignature);
     2052    return rc;
     2053}
     2054
     2055
     2056/**
     2057 * Destroys the parsed signature.
     2058 *
     2059 * @param   pModPe              The PE module.
     2060 * @param   pSignature          The signature data to destroy.
     2061 */
     2062static void rtldrPE_VerifySignatureDestroy(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature)
     2063{
     2064    RTCrPkcs7ContentInfo_Delete(&pSignature->ContentInfo);
     2065    RTMemTmpFree(pSignature);
     2066}
     2067
     2068
     2069/**
     2070 * Decodes the raw signature.
     2071 *
     2072 * @returns IPRT status code.
     2073 * @param   pModPe              The PE module.
     2074 * @param   pSignature          The signature data.
     2075 * @param   pErrInfo            Optional error info buffer.
     2076 */
     2077static int rtldrPE_VerifySignatureDecode(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo)
     2078{
     2079    WIN_CERTIFICATE const  *pEntry = pSignature->pRawData;
     2080    AssertReturn(pEntry->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA, VERR_INTERNAL_ERROR_2);
     2081    AssertReturn(pEntry->wRevision        == WIN_CERT_REVISION_2_0, VERR_INTERNAL_ERROR_2);
     2082
     2083    RTASN1CURSORPRIMARY PrimaryCursor;
     2084    RTAsn1CursorInitPrimary(&PrimaryCursor,
     2085                            &pEntry->bCertificate[0],
     2086                            pEntry->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate),
     2087                            pErrInfo,
     2088                            &g_RTAsn1DefaultAllocator,
     2089                            0,
     2090                            "WinCert");
     2091
     2092    int rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &pSignature->ContentInfo, "CI");
     2093    if (RT_SUCCESS(rc))
     2094    {
     2095        if (RTCrPkcs7ContentInfo_IsSignedData(&pSignature->ContentInfo))
     2096        {
     2097            pSignature->pSignedData = pSignature->ContentInfo.u.pSignedData;
     2098
     2099            /*
     2100             * Decode the authenticode bits.
     2101             */
     2102            if (!strcmp(pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID))
     2103            {
     2104                pSignature->pIndData = pSignature->pSignedData->ContentInfo.u.pIndirectDataContent;
     2105                Assert(pSignature->pIndData);
     2106
     2107                /*
     2108                 * Check that things add up.
     2109                 */
     2110                if (RT_SUCCESS(rc))
     2111                    rc = RTCrPkcs7SignedData_CheckSanity(pSignature->pSignedData,
     2112                                                         RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE
     2113                                                         | RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH
     2114                                                         | RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT,
     2115                                                         pErrInfo, "SD");
     2116                if (RT_SUCCESS(rc))
     2117                    rc = RTCrSpcIndirectDataContent_CheckSanityEx(pSignature->pIndData,
     2118                                                                  pSignature->pSignedData,
     2119                                                                  RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH,
     2120                                                                  pErrInfo);
     2121                if (RT_SUCCESS(rc))
     2122                {
     2123                    PCRTCRX509ALGORITHMIDENTIFIER pDigestAlgorithm = &pSignature->pIndData->DigestInfo.DigestAlgorithm;
     2124                    pSignature->enmDigest = RTCrX509AlgorithmIdentifier_QueryDigestType(pDigestAlgorithm);
     2125                    AssertReturn(pSignature->enmDigest != RTDIGESTTYPE_INVALID, VERR_INTERNAL_ERROR_4); /* Checked above! */
     2126                }
     2127            }
     2128            else
     2129                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID,
     2130                                   "Unknown pSignedData.ContentInfo.ContentType.szObjId value: %s (expected %s)",
     2131                                   pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID);
     2132        }
     2133    }
     2134    return rc;
     2135}
     2136
     2137
     2138static int rtldrPE_VerifyAllPageHashesV2(PRTLDRMODPE pModPe, PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib, RTDIGESTTYPE enmDigest,
     2139                                         void *pvScratch, size_t cbScratch, PRTERRINFO pErrInfo)
     2140{
     2141    AssertReturn(cbScratch >= _4K, VERR_INTERNAL_ERROR_3);
     2142
     2143    /*
     2144     * Calculate the special places.
     2145     */
     2146    RTLDRPEHASHSPECIALS SpecialPlaces;
     2147    int rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo);
     2148    if (RT_FAILURE(rc))
     2149        return rc;
     2150
     2151    uint32_t const cbHash = rtLdrPE_HashGetHashSize(enmDigest);
     2152    uint32_t const cPages = pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb / (cbHash + 4);
     2153    if (cPages * (cbHash + 4) != pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb)
     2154        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW,
     2155                             "Page Hashes V2 size issue: cb=%#x cbHash=%#x",
     2156                             pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb, cbHash);
     2157
     2158    /*
     2159     * Walk the table.
     2160     */
     2161    uint32_t const  cbScratchReadMax = cbScratch & ~(uint32_t)(_4K - 1);
     2162    uint32_t        cbScratchRead    = 0;
     2163    uint32_t        offScratchRead   = 0;
     2164
     2165    uint32_t        offPrev    = 0;
     2166    uint32_t        offSectEnd = pModPe->cbHeaders;
     2167    uint32_t        iSh        = UINT32_MAX;
     2168    uint8_t const  *pbHashTab  = pAttrib->u.pPageHashesV2->RawData.Asn1Core.uData.pu8;
     2169    for (uint32_t iPage = 0; iPage < cPages; iPage++)
     2170    {
     2171        /* Decode the page offset. */
     2172        uint32_t const offFile = RT_MAKE_U32_FROM_U8(pbHashTab[0], pbHashTab[1], pbHashTab[2], pbHashTab[3]);
     2173        if (offFile >= SpecialPlaces.cbToHash)
     2174        {
     2175            /* The last entry is zero. */
     2176            if (   offFile   == SpecialPlaces.cbToHash
     2177                && iPage + 1 == cPages
     2178                && ASMMemIsAll8(pbHashTab + 4, cbHash, 0) == NULL)
     2179                return VINF_SUCCESS;
     2180            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG,
     2181                                 "Page hash entry #%u is beyond the signature table start: %#x, %#x",
     2182                                 iPage, offFile, SpecialPlaces.cbToHash);
     2183        }
     2184        if (offFile < offPrev)
     2185            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED,
     2186                                 "Page hash table is not strictly sorted: entry #%u @%#x, previous @%#x\n",
     2187                                 iPage, offFile, offPrev);
     2188
     2189        /* Figure out how much to read and how much to zero.  Need keep track
     2190           of the on-disk section boundraries. */
     2191        if (offFile >= offSectEnd)
     2192        {
     2193            iSh++;
     2194            if (   iSh < pModPe->cSections
     2195                && offFile - pModPe->paSections[iSh].PointerToRawData < pModPe->paSections[iSh].SizeOfRawData)
     2196                offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData;
     2197            else
     2198            {
     2199                iSh = 0;
     2200                while (   iSh < pModPe->cSections
     2201                       && offFile - pModPe->paSections[iSh].PointerToRawData >= pModPe->paSections[iSh].SizeOfRawData)
     2202                    iSh++;
     2203                if (iSh < pModPe->cSections)
     2204                    offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData;
     2205                else
     2206                    return RTErrInfoSetF(pErrInfo, VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA,
     2207                                         "Page hash entry #%u isn't in any section: %#x", iPage, offFile);
     2208            }
     2209        }
     2210
     2211        uint32_t cbRead = _4K;
     2212        if (offFile + cbRead > offSectEnd)
     2213            cbRead = offSectEnd - offFile;
     2214
     2215        if (offFile + cbRead > SpecialPlaces.cbToHash)
     2216            cbRead = SpecialPlaces.cbToHash - offFile;
     2217
     2218        /* Did we get a cache hit? */
     2219        uint8_t *pbCur = (uint8_t *)pvScratch;
     2220        if (   offFile + cbRead <= offScratchRead + cbScratchRead
     2221            && offFile          >= offScratchRead)
     2222            pbCur += offFile - offScratchRead;
     2223        /* Missed, read more. */
     2224        else
     2225        {
     2226            offScratchRead = offFile;
     2227            cbScratchRead  = offSectEnd - offFile;
     2228            if (cbScratchRead > cbScratchReadMax)
     2229                cbScratchRead = cbScratchReadMax;
     2230            rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbScratchRead, offScratchRead);
     2231            if (RT_FAILURE(rc))
     2232                return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH,
     2233                                     "Page hash read error at %#x: %Rrc (cbScratchRead=%#zx)",
     2234                                     offScratchRead, rc, cbScratchRead);
     2235        }
     2236
     2237        /* Zero any additional bytes in the page. */
     2238        if (cbRead != _4K)
     2239            memset(pbCur + cbRead, 0, _4K - cbRead);
     2240
     2241        /*
     2242         * Hash it.
     2243         */
     2244        RTLDRPEHASHCTXUNION HashCtx;
     2245        rc = rtLdrPE_HashInit(&HashCtx, enmDigest);
     2246        AssertRCReturn(rc, rc);
     2247
     2248        /* Deal with special places. */
     2249        uint32_t       cbLeft = _4K;
     2250        if (offFile < SpecialPlaces.offEndSpecial)
     2251        {
     2252            uint32_t off = offFile;
     2253            if (off < SpecialPlaces.offCksum)
     2254            {
     2255                /* Hash everything up to the checksum. */
     2256                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbLeft);
     2257                rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
     2258                pbCur  += cbChunk;
     2259                cbLeft -= cbChunk;
     2260                off    += cbChunk;
     2261            }
     2262
     2263            if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum)
     2264            {
     2265                /* Skip the checksum */
     2266                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbLeft);
     2267                pbCur  += cbChunk;
     2268                cbLeft -= cbChunk;
     2269                off    += cbChunk;
     2270            }
     2271
     2272            if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum)
     2273            {
     2274                /* Hash everything between the checksum and the data dir entry. */
     2275                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbLeft);
     2276                rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
     2277                pbCur  += cbChunk;
     2278                cbLeft -= cbChunk;
     2279                off    += cbChunk;
     2280            }
     2281
     2282            if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir)
     2283            {
     2284                /* Skip the security data directory entry. */
     2285                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbLeft);
     2286                pbCur  += cbChunk;
     2287                cbLeft -= cbChunk;
     2288                off    += cbChunk;
     2289            }
     2290        }
     2291
     2292        rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbLeft);
     2293
     2294        /*
     2295         * Finish the hash calculation and compare the result.
     2296         */
     2297        RTLDRPEHASHRESUNION HashRes;
     2298        rtLdrPE_HashFinalize(&HashCtx, enmDigest, &HashRes);
     2299
     2300        pbHashTab += 4;
     2301        if (memcmp(pbHashTab, &HashRes, cbHash) != 0)
     2302            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_MISMATCH,
     2303                                 "Page hash v2 failed for page #%u, @%#x, %#x bytes: %.*Rhxs != %.*Rhxs",
     2304                                 iPage, offFile, cbRead, (size_t)cbHash, pbHashTab, (size_t)cbHash, &HashRes);
     2305        pbHashTab += cbHash;
     2306        offPrev = offFile;
     2307    }
     2308
     2309    return VINF_SUCCESS;
     2310}
     2311
     2312
     2313/**
     2314 * Validates the image hash, including page hashes if present.
     2315 *
     2316 * @returns IPRT status code.
     2317 * @param   pModPe              The PE module.
     2318 * @param   pSignature          The decoded signature data.
     2319 * @param   pErrInfo            Optional error info buffer.
     2320 */
     2321static int rtldrPE_VerifySignatureValidateHash(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo)
     2322{
     2323    AssertReturn(pSignature->enmDigest > RTDIGESTTYPE_INVALID && pSignature->enmDigest < RTDIGESTTYPE_END, VERR_INTERNAL_ERROR_4);
     2324    AssertPtrReturn(pSignature->pIndData, VERR_INTERNAL_ERROR_5);
     2325    AssertReturn(RTASN1CORE_IS_PRESENT(&pSignature->pIndData->DigestInfo.Digest.Asn1Core), VERR_INTERNAL_ERROR_5);
     2326    AssertPtrReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, VERR_INTERNAL_ERROR_5);
     2327
     2328    uint32_t const cbHash = rtLdrPE_HashGetHashSize(pSignature->enmDigest);
     2329    AssertReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.cb == cbHash, VERR_INTERNAL_ERROR_5);
     2330
     2331    /*
     2332     * Allocate a temporary memory buffer.
     2333     */
     2334#ifdef IN_RING0
     2335    uint32_t    cbScratch = _256K;
     2336#else
     2337    uint32_t    cbScratch = _1M;
     2338#endif
     2339    void       *pvScratch = RTMemTmpAlloc(cbScratch);
     2340    if (!pvScratch)
     2341    {
     2342        cbScratch = _4K;
     2343        pvScratch = RTMemTmpAlloc(cbScratch);
     2344        if (!pvScratch)
     2345            return RTErrInfoSet(pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate 4KB of scratch space for hashing image.");
     2346    }
     2347
     2348    /*
     2349     * Calculate and compare the full image hash.
     2350     */
     2351    int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, pSignature->enmDigest,
     2352                                     &pSignature->HashCtx, &pSignature->HashRes, pErrInfo);
     2353    if (RT_SUCCESS(rc))
     2354    {
     2355        if (!memcmp(&pSignature->HashRes, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, cbHash))
     2356        {
     2357            /*
     2358             * Compare the page hashes if present.
     2359             */
     2360            PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib = RTCrSpcIndirectDataContent_GetPeImageHashesV2(pSignature->pIndData);
     2361            if (pAttrib)
     2362                rc = rtldrPE_VerifyAllPageHashesV2(pModPe, pAttrib, pSignature->enmDigest, pvScratch, cbScratch, pErrInfo);
     2363
     2364            return rc;
     2365        }
     2366        rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_IMAGE_HASH_MISMATCH,
     2367                           "Full image signature mismatch: %.*Rhxs, expected %.*Rhxs",
     2368                           cbHash, &pSignature->HashRes,
     2369                           cbHash, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv);
     2370    }
     2371
     2372    RTMemTmpFree(pvScratch);
     2373    return rc;
     2374}
     2375
     2376#endif /* !IPRT_WITHOUT_LDR_VERIFY */
     2377
     2378
     2379/** @interface_method_impl{RTLDROPS,pfnVerifySignature} */
     2380static DECLCALLBACK(int) rtldrPE_VerifySignature(PRTLDRMODINTERNAL pMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser,
     2381                                                 PRTERRINFO pErrInfo)
     2382{
     2383#ifndef IPRT_WITHOUT_LDR_VERIFY
     2384    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     2385
     2386    int rc = rtldrPE_VerifySignatureImagePrecoditions(pModPe, pErrInfo);
     2387    if (RT_SUCCESS(rc))
     2388    {
     2389        PRTLDRPESIGNATURE pSignature = NULL;
     2390        rc = rtldrPE_VerifySignatureRead(pModPe, &pSignature, pErrInfo);
     2391        if (RT_SUCCESS(rc))
     2392        {
     2393            rc = rtldrPE_VerifySignatureDecode(pModPe, pSignature, pErrInfo);
     2394            if (RT_SUCCESS(rc))
     2395                rc = rtldrPE_VerifySignatureValidateHash(pModPe, pSignature, pErrInfo);
     2396            if (RT_SUCCESS(rc))
     2397            {
     2398                rc = pfnCallback(&pModPe->Core, RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA,
     2399                                 &pSignature->ContentInfo, sizeof(pSignature->ContentInfo),
     2400                                 pErrInfo, pvUser);
     2401            }
     2402            rtldrPE_VerifySignatureDestroy(pModPe, pSignature);
     2403        }
     2404    }
     2405    return rc;
     2406#else
     2407    return VERR_NOT_SUPPORTED;
     2408#endif
     2409}
     2410
     2411
     2412
     2413/**  @interface_method_impl{RTLDROPS,pfnHashImage}  */
     2414static DECLCALLBACK(int) rtldrPE_HashImage(PRTLDRMODINTERNAL pMod, RTDIGESTTYPE enmDigest, char *pszDigest, size_t cbDigest)
     2415{
     2416    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     2417
     2418    /*
     2419     * Allocate a temporary memory buffer.
     2420     */
     2421    uint32_t    cbScratch = _16K;
     2422    void       *pvScratch = RTMemTmpAlloc(cbScratch);
     2423    if (!pvScratch)
     2424    {
     2425        cbScratch = _4K;
     2426        pvScratch = RTMemTmpAlloc(cbScratch);
     2427        if (!pvScratch)
     2428            return VERR_NO_TMP_MEMORY;
     2429    }
     2430
     2431    /*
     2432     * Do the hashing.
     2433     */
     2434    RTLDRPEHASHCTXUNION HashCtx;
     2435    RTLDRPEHASHRESUNION HashRes;
     2436    int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, enmDigest, &HashCtx, &HashRes, NULL);
     2437    if (RT_SUCCESS(rc))
     2438    {
     2439        /*
     2440         * Format the digest into as human readable hash string.
     2441         */
     2442        switch (enmDigest)
     2443        {
     2444            case RTDIGESTTYPE_SHA512:  rc = RTSha512ToString(HashRes.abSha512, pszDigest, cbDigest); break;
     2445            case RTDIGESTTYPE_SHA256:  rc = RTSha256ToString(HashRes.abSha256, pszDigest, cbDigest); break;
     2446            case RTDIGESTTYPE_SHA1:    rc = RTSha1ToString(HashRes.abSha1, pszDigest, cbDigest); break;
     2447            case RTDIGESTTYPE_MD5:     rc = RTMd5ToString(HashRes.abMd5, pszDigest, cbDigest); break;
     2448            default:                   AssertFailedReturn(VERR_INTERNAL_ERROR_3);
     2449        }
     2450    }
     2451    return rc;
     2452}
     2453
     2454
    15142455/** @copydoc RTLDROPS::pfnDone */
    15152456static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
     
    15232464    return VINF_SUCCESS;
    15242465}
     2466
    15252467
    15262468/** @copydoc RTLDROPS::pfnClose */
     
    15662508        NULL,
    15672509        rtldrPE_QueryProp,
     2510        rtldrPE_VerifySignature,
     2511        rtldrPE_HashImage,
    15682512        42
    15692513    },
     
    15972541        NULL,
    15982542        rtldrPE_QueryProp,
     2543        rtldrPE_VerifySignature,
     2544        rtldrPE_HashImage,
    15992545        42
    16002546    },
     
    16602606     * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
    16612607     */
    1662     IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
    1663     IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
    1664 
    1665     pLoadCfg64->SEHandlerCount             = pLoadCfg32->SEHandlerCount;
    1666     pLoadCfg64->SEHandlerTable             = pLoadCfg32->SEHandlerTable;
    1667     pLoadCfg64->SecurityCookie             = pLoadCfg32->SecurityCookie;
    1668     pLoadCfg64->EditList                   = pLoadCfg32->EditList;
    1669     pLoadCfg64->Reserved1                  = pLoadCfg32->Reserved1;
    1670     pLoadCfg64->CSDVersion                 = pLoadCfg32->CSDVersion;
    1671     pLoadCfg64->ProcessHeapFlags           = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
    1672     pLoadCfg64->ProcessAffinityMask        = pLoadCfg32->ProcessAffinityMask;
    1673     pLoadCfg64->VirtualMemoryThreshold     = pLoadCfg32->VirtualMemoryThreshold;
    1674     pLoadCfg64->MaximumAllocationSize      = pLoadCfg32->MaximumAllocationSize;
    1675     pLoadCfg64->LockPrefixTable            = pLoadCfg32->LockPrefixTable;
    1676     pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
    1677     uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold;
    1678     pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold;
     2608    IMAGE_LOAD_CONFIG_DIRECTORY32_V3 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32_V3 volatile *)pLoadCfg;
     2609    IMAGE_LOAD_CONFIG_DIRECTORY64_V3 volatile *pLoadCfg64 = pLoadCfg;
     2610
     2611    pLoadCfg64->GuardFlags                  = pLoadCfg32->GuardFlags;
     2612    pLoadCfg64->GuardCFFunctionCount        = pLoadCfg32->GuardCFFunctionCount;
     2613    pLoadCfg64->GuardCFFunctionTable        = pLoadCfg32->GuardCFFunctionTable;
     2614    pLoadCfg64->Reserved2                   = pLoadCfg32->Reserved2;
     2615    pLoadCfg64->GuardCFCCheckFunctionPointer= pLoadCfg32->GuardCFCCheckFunctionPointer;
     2616    pLoadCfg64->SEHandlerCount              = pLoadCfg32->SEHandlerCount;
     2617    pLoadCfg64->SEHandlerTable              = pLoadCfg32->SEHandlerTable;
     2618    pLoadCfg64->SecurityCookie              = pLoadCfg32->SecurityCookie;
     2619    pLoadCfg64->EditList                    = pLoadCfg32->EditList;
     2620    pLoadCfg64->Reserved1                   = pLoadCfg32->Reserved1;
     2621    pLoadCfg64->CSDVersion                  = pLoadCfg32->CSDVersion;
     2622    pLoadCfg64->ProcessHeapFlags            = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
     2623    pLoadCfg64->ProcessAffinityMask         = pLoadCfg32->ProcessAffinityMask;
     2624    pLoadCfg64->VirtualMemoryThreshold      = pLoadCfg32->VirtualMemoryThreshold;
     2625    pLoadCfg64->MaximumAllocationSize       = pLoadCfg32->MaximumAllocationSize;
     2626    pLoadCfg64->LockPrefixTable             = pLoadCfg32->LockPrefixTable;
     2627    pLoadCfg64->DeCommitTotalFreeThreshold  = pLoadCfg32->DeCommitTotalFreeThreshold;
     2628    uint32_t u32DeCommitFreeBlockThreshold  = pLoadCfg32->DeCommitFreeBlockThreshold;
     2629    pLoadCfg64->DeCommitFreeBlockThreshold  = u32DeCommitFreeBlockThreshold;
    16792630    /* the rest is equal. */
    16802631    Assert(     RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold)
     
    17202671    /* This restriction needs to be implemented elsewhere. */
    17212672    if (   (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
    1722         && !(fFlags & RTLDR_O_FOR_DEBUG))
     2673        && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
    17232674    {
    17242675        Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
     
    18562807
    18572808            case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:  // 13
     2809                if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
     2810                    break;
    18582811                Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
    18592812                     pszLogName, i, pDir->VirtualAddress, pDir->Size));
     
    18702823                    return VERR_LDRPE_CERT_MALFORMED;
    18712824                }
    1872                 if (pDir->Size >= _1M)
     2825                if (pDir->Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE)
    18732826                {
    18742827                    Log(("rtldrPEOpen: %s: Security directory is too large: %#x bytes\n", pszLogName, i, pDir->Size));
     
    18942847
    18952848            case IMAGE_DIRECTORY_ENTRY_TLS:           // 9
     2849                if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
     2850                    break;
    18962851                Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
    18972852                     pszLogName, i, pDir->VirtualAddress, pDir->Size));
     
    18992854
    19002855            case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:// 14
     2856                if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
     2857                    break;
    19012858                Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
    19022859                     pszLogName, i, pDir->VirtualAddress, pDir->Size));
     
    19452902    for (unsigned cSHdrsLeft = cSections;  cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
    19462903    {
    1947         const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);
     2904        const unsigned iSH = (unsigned)(pSH - &paSections[0]); NOREF(iSH);
    19482905        Log3(("RTLdrPE: #%d '%-8.8s'  Characteristics: %08RX32\n"
    19492906              "RTLdrPE: VirtAddr: %08RX32  VirtSize: %08RX32\n"
     
    21103067
    21113068/**
    2112  * Validates the data of some selected data directories entries.
    2113  *
    2114  * This requires a valid section table and thus has to wait
    2115  * till after we've read and validated it.
     3069 * Validates the data of some selected data directories entries and remember
     3070 * important bits for later.
     3071 *
     3072 * This requires a valid section table and thus has to wait till after we've
     3073 * read and validated it.
    21163074 *
    21173075 * @returns iprt status code.
     
    21203078 * @param   fFlags      Loader flags, RTLDR_O_XXX.
    21213079 */
    2122 static int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
     3080static int rtldrPEValidateDirectoriesAndRememberStuff(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
    21233081{
    21243082    const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
     
    21363094    if (Dir.Size)
    21373095    {
    2138         const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
    2139             ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
    2140             : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64);
    2141         if (    Dir.Size != cbExpect
    2142             && (    cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
    2143                 &&  Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable))
    2144            )
    2145         {
    2146             Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n",
    2147                  pszLogName, Dir.Size, cbExpect));
     3096        const size_t cbExpectV3 = !pModPe->f64Bit
     3097                                ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V3)
     3098                                : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V3);
     3099        const size_t cbExpectV2 = !pModPe->f64Bit
     3100                                ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V2)
     3101                                : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2);
     3102        const size_t cbExpectV1 = !pModPe->f64Bit
     3103                                ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V1)
     3104                                : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2) /*No V1*/;
     3105
     3106        if (   Dir.Size != cbExpectV3
     3107            && Dir.Size != cbExpectV2
     3108            && Dir.Size != cbExpectV1)
     3109        {
     3110            Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d, %d, or %d.\n",
     3111                 pszLogName, Dir.Size, cbExpectV3, cbExpectV2, cbExpectV1));
    21483112            return VERR_LDRPE_LOAD_CONFIG_SIZE;
    21493113        }
     
    21583122        rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
    21593123
    2160         if (u.Cfg64.Size != cbExpect)
    2161         {
    2162             Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
    2163                  pszLogName, u.Cfg64.Size, cbExpect));
    2164             return VERR_LDRPE_LOAD_CONFIG_SIZE;
    2165         }
    2166         if (u.Cfg64.LockPrefixTable)
     3124        if (u.Cfg64.Size != Dir.Size)
     3125        {
     3126            /* Kludge, seen ati shipping 32-bit DLLs and EXEs with Dir.Size=0x40
     3127               and Cfg64.Size=0x5c or 0x48.  Windows seems to deal with it, so
     3128               lets do so as well. */
     3129            if (   Dir.Size < u.Cfg64.Size
     3130                && (   u.Cfg64.Size == cbExpectV3
     3131                    || u.Cfg64.Size == cbExpectV2) )
     3132            {
     3133                Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the ATI kludge\n",
     3134                     pszLogName, u.Cfg64.Size, Dir.Size));
     3135                Dir.Size = u.Cfg64.Size;
     3136                memset(&u.Cfg64, 0, sizeof(u.Cfg64));
     3137                rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
     3138                if (RT_FAILURE(rc))
     3139                    return rc;
     3140                rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
     3141            }
     3142            if (u.Cfg64.Size != Dir.Size)
     3143            {
     3144                Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
     3145                     pszLogName, u.Cfg64.Size, Dir.Size));
     3146                return VERR_LDRPE_LOAD_CONFIG_SIZE;
     3147            }
     3148        }
     3149        if (u.Cfg64.LockPrefixTable && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
    21673150        {
    21683151            Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
     
    21793162        }
    21803163#endif
    2181         if (u.Cfg64.EditList)
     3164        if (u.Cfg64.EditList && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
    21823165        {
    21833166            Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
     
    21853168            return VERR_BAD_EXE_FORMAT;
    21863169        }
     3170        /** @todo GuardCFC? Possibly related to:
     3171         *         http://research.microsoft.com/pubs/69217/ccs05-cfi.pdf
     3172         * Not trusting something designed by bakas who don't know how to modify a
     3173         * structure without messing up its natural alignment. */
     3174        if (    (   u.Cfg64.GuardCFCCheckFunctionPointer
     3175                 || u.Cfg64.Reserved2
     3176                 || u.Cfg64.GuardCFFunctionTable
     3177                 || u.Cfg64.GuardCFFunctionCount
     3178                 || u.Cfg64.GuardFlags)
     3179            && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
     3180        {
     3181            Log(("rtldrPEOpen: %s: load cfg dir: Guard stuff: %RX64,%RX64,%RX64,%RX64,%RX32!\n",
     3182                 pszLogName, u.Cfg64.GuardCFCCheckFunctionPointer, u.Cfg64.Reserved2,
     3183                 u.Cfg64.GuardCFFunctionTable, u.Cfg64.GuardCFFunctionCount, u.Cfg64.GuardFlags));
     3184            return VERR_BAD_EXE_FORMAT;
     3185        }
    21873186    }
    21883187
     
    21923191     */
    21933192    Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
    2194     if (Dir.Size && !(fFlags & RTLDR_O_FOR_DEBUG))
     3193    if (Dir.Size)
    21953194    {
    21963195        PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
     
    22003199        if (RT_SUCCESS(rc))
    22013200        {
    2202             uint32_t         off  = 0;
    2203             PWIN_CERTIFICATE pCur = pFirst;
     3201            uint32_t off  = 0;
    22043202            do
    22053203            {
     3204                PWIN_CERTIFICATE pCur = (PWIN_CERTIFICATE)((uint8_t *)pFirst + off);
     3205
    22063206                /* validate the members. */
    2207                 uint32_t const cbCur = RT_ALIGN_32(pCur->dwLength, 8);
    2208                 if (   cbCur < sizeof(WIN_CERTIFICATE)
    2209                     || cbCur + off > RT_ALIGN_32(Dir.Size, 8))
     3207                if (   pCur->dwLength < sizeof(WIN_CERTIFICATE)
     3208                    || pCur->dwLength + off > Dir.Size)
    22103209                {
    22113210                    Log(("rtldrPEOpen: %s: cert at %#x/%#x: dwLength=%#x\n", pszLogName, off, Dir.Size, pCur->dwLength));
     
    22333232                }
    22343233
    2235                 /** @todo Rainy Day: Implement further verification using openssl. */
     3234                /* Remember the first signed data certificate. */
     3235                if (   pCur->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA
     3236                    && pModPe->offPkcs7SignedData == 0)
     3237                {
     3238                    pModPe->offPkcs7SignedData = Dir.VirtualAddress
     3239                                               + (uint32_t)((uintptr_t)&pCur->bCertificate[0] - (uintptr_t)pFirst);
     3240                    pModPe->cbPkcs7SignedData  = pCur->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate);
     3241                }
    22363242
    22373243                /* next */
    2238                 off += cbCur;
    2239                 pCur = (PWIN_CERTIFICATE)((uint8_t *)pCur + cbCur);
     3244                off += RT_ALIGN(pCur->dwLength, WIN_CERTIFICATE_ALIGNMENT);
    22403245            } while (off < Dir.Size);
    22413246        }
     
    22593264 * @param   offNtHdrs   The offset of the NT headers (where you find "PE\0\0").
    22603265 * @param   phLdrMod    Where to store the handle.
    2261  */
    2262 int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
     3266 * @param   pErrInfo    Where to return extended error information. Optional.
     3267 */
     3268int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs,
     3269                PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
    22633270{
    22643271    /*
     
    23493356                pModPe->cbHeaders     = OptHdr.SizeOfHeaders;
    23503357                pModPe->uTimestamp    = FileHdr.TimeDateStamp;
     3358                pModPe->f64Bit        = FileHdr.SizeOfOptionalHeader == sizeof(OptHdr);
    23513359                pModPe->ImportDir     = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    23523360                pModPe->RelocDir      = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
    23533361                pModPe->ExportDir     = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    23543362                pModPe->DebugDir      = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
     3363                pModPe->SecurityDir   = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
     3364                pModPe->fDllCharacteristics = OptHdr.DllCharacteristics;
    23553365
    23563366                /*
    23573367                 * Perform validation of some selected data directories which requires
    2358                  * inspection of the actual data.
     3368                 * inspection of the actual data.  This also saves some certificate
     3369                 * information.
    23593370                 */
    2360                 rc = rtldrPEValidateDirectories(pModPe, &OptHdr, fFlags);
     3371                rc = rtldrPEValidateDirectoriesAndRememberStuff(pModPe, &OptHdr, fFlags);
    23613372                if (RT_SUCCESS(rc))
    23623373                {
  • trunk/src/VBox/Runtime/common/ldr/ldrkStuff.cpp

    r49045 r51770  
    838838
    839839/** @interface_method_impl{RTLDROPS,pfnQueryProp} */
    840 static DECLCALLBACK(int) rtkldr_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf)
     840static DECLCALLBACK(int) rtkldr_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet)
    841841{
    842842    PRTLDRMODKLDR pThis = (PRTLDRMODKLDR)pMod;
     
    881881    rtkldr_ReadDbgInfo,
    882882    rtkldr_QueryProp,
     883    NULL,
     884    NULL,
    883885    42
    884886};
     
    893895 * @param   enmArch     CPU architecture specifier for the image to be loaded.
    894896 * @param   phLdrMod    Where to store the handle.
     897 * @param   pErrInfo    Where to return extended error information. Optional.
    895898 */
    896 int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod)
     899int rtldrkLdrOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
    897900{
    898901    /* Convert enmArch to k-speak. */
  • trunk/src/VBox/Runtime/common/log/log.cpp

    r50915 r51770  
    26092609RT_EXPORT_SYMBOL(RTLogPrintfV);
    26102610
     2611
     2612/**
     2613 * Dumper vprintf-like function outputting to a logger.
     2614 *
     2615 * @param   pvUser          Pointer to the logger instance to use, NULL for
     2616 *                          default instance.
     2617 * @param   pszFormat       Format string.
     2618 * @param   va              Format arguments.
     2619 */
     2620RTDECL(void) RTLogDumpPrintfV(void *pvUser, const char *pszFormat, va_list va)
     2621{
     2622    RTLogLoggerV((PRTLOGGER)pvUser, pszFormat, va);
     2623}
     2624RT_EXPORT_SYMBOL(RTLogDumpPrintfV);
     2625
     2626
    26112627#ifdef IN_RING3
    26122628
  • trunk/src/VBox/Runtime/common/misc/sg.cpp

    r44529 r51770  
    4848    }
    4949
     50#ifndef RDESKTOP
    5051    AssertReleaseMsg(      pSgBuf->cbSegLeft <= 32 * _1M
    5152                     &&    (uintptr_t)pSgBuf->pvSegCur                     >= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg
     
    5455                      pSgBuf->idxSeg, pSgBuf->cSegs, pSgBuf->pvSegCur, pSgBuf->cbSegLeft,
    5556                      pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg, pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg));
     57#endif
    5658
    5759    cbData = RT_MIN(*pcbData, pSgBuf->cbSegLeft);
  • trunk/src/VBox/Runtime/common/string/RTStrPrintHexBytes.cpp

    r44529 r51770  
    55
    66/*
    7  * Copyright (C) 2009-2010 Oracle Corporation
     7 * Copyright (C) 2009-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3838RTDECL(int) RTStrPrintHexBytes(char *pszBuf, size_t cchBuf, void const *pv, size_t cb, uint32_t fFlags)
    3939{
    40     AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
     40    AssertReturn(!(fFlags & ~RTSTRPRINTHEXBYTES_F_UPPER), VERR_INVALID_PARAMETER);
    4141    AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
    4242    AssertReturn(cb * 2 >= cb, VERR_BUFFER_OVERFLOW);
     
    4545        AssertPtrReturn(pv, VERR_INVALID_POINTER);
    4646
     47    static char const s_szHexDigitsLower[17] = "0123456789abcdef";
     48    static char const s_szHexDigitsUpper[17] = "0123456789ABCDEF";
     49    const char *pszHexDigits = !(fFlags & RTSTRPRINTHEXBYTES_F_UPPER) ? s_szHexDigitsLower : s_szHexDigitsUpper;
     50
    4751    uint8_t const *pb = (uint8_t const *)pv;
    4852    while (cb-- > 0)
    4953    {
    50         static char const s_szHexDigits[17] = "0123456789abcdef";
    5154        uint8_t b = *pb++;
    52         *pszBuf++ = s_szHexDigits[b >> 4];
    53         *pszBuf++ = s_szHexDigits[b & 0xf];
     55        *pszBuf++ = pszHexDigits[b >> 4];
     56        *pszBuf++ = pszHexDigits[b & 0xf];
    5457    }
    5558    *pszBuf = '\0';
  • trunk/src/VBox/Runtime/common/string/base64.cpp

    r44529 r51770  
    3535#include <iprt/err.h>
    3636#include <iprt/ctype.h>
     37#include <iprt/string.h>
    3738#ifdef RT_STRICT
    3839# include <iprt/asm.h>
     
    120121
    121122
    122 /**
    123  * Calculates the decoded data size for a Base64 encoded string.
    124  *
    125  * @returns The length in bytes. -1 if the encoding is bad.
    126  *
    127  * @param   pszString           The Base64 encoded string.
    128  * @param   ppszEnd             If not NULL, this will point to the first char
    129  *                              following the Base64 encoded text block. If
    130  *                              NULL the entire string is assumed to be Base64.
    131  */
    132 RTDECL(ssize_t) RTBase64DecodedSize(const char *pszString, char **ppszEnd)
     123RTDECL(ssize_t) RTBase64DecodedSizeEx(const char *pszString, size_t cchStringMax, char **ppszEnd)
    133124{
    134125#ifdef RT_STRICT
     
    144135    AssertCompile(sizeof(char) == sizeof(uint8_t));
    145136
    146     while ((ch = *pszString))
     137    while (cchStringMax > 0 && (ch = *pszString))
    147138    {
    148139        u8 = g_au8CharToVal[ch];
     
    154145        /* advance */
    155146        pszString++;
     147        cchStringMax--;
    156148    }
    157149
     
    166158        c6Bits++;
    167159        pszString++;
    168         while ((ch = *pszString))
     160        cchStringMax--;
     161        while (cchStringMax > 0 && (ch = *pszString))
    169162        {
    170163            u8 = g_au8CharToVal[ch];
     
    177170            }
    178171            pszString++;
     172            cchStringMax--;
    179173        }
    180174        if (cbPad >= 3)
     
    216210    return cb;
    217211}
     212RT_EXPORT_SYMBOL(RTBase64DecodedSizeEx);
     213
     214
     215RTDECL(ssize_t) RTBase64DecodedSize(const char *pszString, char **ppszEnd)
     216{
     217    return RTBase64DecodedSizeEx(pszString, RTSTR_MAX, ppszEnd);
     218}
    218219RT_EXPORT_SYMBOL(RTBase64DecodedSize);
    219220
    220221
    221 /**
    222  * Decodes a Base64 encoded string into the buffer supplied by the caller.
    223  *
    224  * @returns IPRT status code.
    225  * @retval  VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not
    226  *          be set, nor will ppszEnd.
    227  * @retval  VERR_INVALID_BASE64_ENCODING if the encoding is wrong.
    228  *
    229  * @param   pszString       The Base64 string. Whether the entire string or
    230  *                          just the start of the string is in Base64 depends
    231  *                          on whether ppszEnd is specified or not.
    232  * @param   pvData          Where to store the decoded data.
    233  * @param   cbData          The size of the output buffer that pvData points to.
    234  * @param   pcbActual       Where to store the actual number of bytes returned.
    235  *                          Optional.
    236  * @param   ppszEnd         Indicates that the string may contain other stuff
    237  *                          after the Base64 encoded data when not NULL. Will
    238  *                          be set to point to the first char that's not part of
    239  *                          the encoding. If NULL the entire string must be part
    240  *                          of the Base64 encoded data.
    241  */
    242 RTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd)
     222RTDECL(int) RTBase64DecodeEx(const char *pszString, size_t cchStringMax, void *pvData, size_t cbData,
     223                             size_t *pcbActual, char **ppszEnd)
    243224{
    244225#ifdef RT_STRICT
     
    251232    uint8_t     u8Trio[3] = { 0, 0, 0 }; /* shuts up gcc */
    252233    uint8_t    *pbData    = (uint8_t *)pvData;
    253     uint8_t     u8        = BASE64_INVALID;
     234    uint8_t     u8;
    254235    unsigned    c6Bits    = 0;
    255236    unsigned    ch;
     
    259240    {
    260241        /* The first 6-bit group. */
    261         while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
    262             pszString++;
     242        while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE)
     243            pszString++, cchStringMax--;
    263244        if (u8 >= 64)
    264245        {
     
    268249        u8Trio[0] = u8 << 2;
    269250        pszString++;
     251        cchStringMax--;
    270252
    271253        /* The second 6-bit group. */
    272         while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
    273             pszString++;
     254        while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE)
     255            pszString++, cchStringMax--;
    274256        if (u8 >= 64)
    275257        {
     
    280262        u8Trio[1]  = u8 << 4;
    281263        pszString++;
     264        cchStringMax--;
    282265
    283266        /* The third 6-bit group. */
    284         while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
    285             pszString++;
     267        u8 = BASE64_INVALID;
     268        while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE)
     269            pszString++, cchStringMax--;
    286270        if (u8 >= 64)
    287271        {
     
    292276        u8Trio[2]  = u8 << 6;
    293277        pszString++;
     278        cchStringMax--;
    294279
    295280        /* The fourth 6-bit group. */
    296         while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
    297             pszString++;
     281        u8 = BASE64_INVALID;
     282        while ((u8 = cchStringMax > 0 ? g_au8CharToVal[ch = *pszString] : BASE64_INVALID) == BASE64_SPACE)
     283            pszString++, cchStringMax--;
    298284        if (u8 >= 64)
    299285        {
     
    303289        u8Trio[2] |= u8;
    304290        pszString++;
     291        cchStringMax--;
    305292
    306293        /* flush the trio */
     
    323310        cbPad = 1;
    324311        pszString++;
    325         while ((ch = *pszString))
     312        cchStringMax--;
     313        while (cchStringMax > 0 && (ch = *pszString))
    326314        {
    327315            u8 = g_au8CharToVal[ch];
     
    333321            }
    334322            pszString++;
     323            cchStringMax--;
    335324        }
    336325        if (cbPad >= 3)
     
    399388        *pcbActual = pbData - (uint8_t *)pvData;
    400389    return VINF_SUCCESS;
     390}
     391RT_EXPORT_SYMBOL(RTBase64DecodeEx);
     392
     393
     394RTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd)
     395{
     396    return RTBase64DecodeEx(pszString, RTSTR_MAX, pvData, cbData, pcbActual, ppszEnd);
    401397}
    402398RT_EXPORT_SYMBOL(RTBase64Decode);
  • trunk/src/VBox/Runtime/common/string/uniread.cpp

    r48935 r51770  
    3535#include <string.h>
    3636#include <stdlib.h>
     37#ifdef _MSC_VER
     38# include <direct.h>
     39#else
     40# include <unistd.h>
     41#endif
    3742
    3843
     
    4045*   Global Variables                                                           *
    4146*******************************************************************************/
    42 /** When set, no output is produced.  Very useful when debugging ths code. */
    43 static bool g_fQuiet = false;
    4447/** The file we're currently parsing. */
    4548static const char *g_pszCurFile;
    4649/** The current line number. */
    4750static unsigned g_iLine;
     51/** The current output file. */
     52static FILE *g_pCurOutFile;
    4853
    4954
     
    884889    //if (pInfo->???)
    885890    //    AppendFlag(pszFlags, "RTUNI_BSPACE");
     891#if 0
    886892    if (pInfo->fInvNFD_QC != 0 || pInfo->fInvNFC_QC != 0)
    887893    {
     
    894900    else if (pInfo->paDecompositionMapping && !*pInfo->pszDecompositionType)
    895901        fprintf(stderr, "uniread: U+%05X is not QC_NFX but has canonical mappings.\n", pInfo->CodePoint);
     902#endif
    896903
    897904    if (!*pszFlags)
     
    906913
    907914/**
     915 * Closes the primary output stream.
     916 */
     917static int Stream1Close(void)
     918{
     919    if (g_pCurOutFile && g_pCurOutFile != stdout && g_pCurOutFile != stderr)
     920    {
     921        if (fclose(g_pCurOutFile) != 0)
     922        {
     923            fprintf(stderr, "Error closing output file.\n");
     924            return -1;
     925        }
     926    }
     927    g_pCurOutFile = NULL;
     928    return 0;
     929}
     930
     931
     932/**
     933 * Initializes the 1st stream to output to a given file.
     934 */
     935static int Stream1Init(const char *pszName)
     936{
     937    int rc = Stream1Close();
     938    if (!rc)
     939    {
     940        g_pCurOutFile = fopen(pszName, "w");
     941        if (!g_pCurOutFile)
     942        {
     943            fprintf(stderr, "Error opening output file '%s'.\n", pszName);
     944            rc = -1;
     945        }
     946    }
     947    return rc;
     948}
     949
     950
     951/**
    908952 * printf wrapper for the primary output stream.
    909953 *
     
    917961    va_list va;
    918962    va_start(va, pszFormat);
    919     if (!g_fQuiet)
    920         cch = vfprintf(stdout, pszFormat, va);
    921     else
    922         cch = (int)strlen(pszFormat);
     963    cch = vfprintf(g_pCurOutFile, pszFormat, va);
    923964    va_end(va);
    924965    return cch;
     
    9741015 * Print the unidata.cpp file header and include list.
    9751016 */
    976 int PrintHeader(const char *argv0)
    977 {
    978     Stream1Printf("/** @file\n"
    979                   " *\n"
     1017int PrintHeader(const char *argv0, const char *pszBaseDir)
     1018{
     1019    char szBuf[1024];
     1020    if (!pszBaseDir)
     1021    {
     1022        memset(szBuf, 0, sizeof(szBuf));
     1023#ifdef _MSC_VER
     1024        _getcwd(szBuf, sizeof(szBuf));
     1025#else
     1026        getcwd(szBuf, sizeof(szBuf));
     1027#endif
     1028        pszBaseDir = szBuf;
     1029    }
     1030
     1031    Stream1Printf("/* $" "Id" "$ */\n"
     1032                  "/** @file\n"
    9801033                  " * IPRT - Unicode Tables.\n"
    9811034                  " *\n"
    982                   " * Automatically Generated by %s (" __DATE__ " " __TIME__ ")\n"
     1035                  " * Automatically Generated from %s\n"
     1036                  " * by %s (" __DATE__ " " __TIME__ ")\n"
    9831037                  " */\n"
    9841038                  "\n"
    9851039                  "/*\n"
    986                   " * Copyright (C) 2006-2010 Oracle Corporation\n"
     1040                  " * Copyright (C) 2006-2014 Oracle Corporation\n"
    9871041                  " *\n"
    9881042                  " * This file is part of VirtualBox Open Source Edition (OSE), as\n"
     
    10061060                  "#include <iprt/uni.h>\n"
    10071061                  "\n",
    1008                   argv0);
     1062                  pszBaseDir, argv0);
    10091063    return 0;
    10101064}
     
    10201074     */
    10211075    Stream2Init();
    1022     Stream2Printf("const RTUNIFLAGSRANGE g_aRTUniFlagsRanges[] =\n"
     1076    Stream2Printf("RT_DECL_DATA_CONST(const RTUNIFLAGSRANGE) g_aRTUniFlagsRanges[] =\n"
    10231077                  "{\n");
    10241078    RTUNICP i = 0;
     
    10471101            if (iStart < 0)
    10481102            {
    1049                 Stream1Printf("static const uint8_t g_afRTUniFlags0x%06x[] = \n"
     1103                Stream1Printf("static const uint8_t g_afRTUniFlags0x%06x[] =\n"
    10501104                              "{\n", i);
    10511105                iStart = i;
     
    10691123{
    10701124    Stream2Init();
    1071     Stream2Printf("const RTUNICASERANGE g_aRTUniUpperRanges[] =\n"
     1125    Stream2Printf("RT_DECL_DATA_CONST(const RTUNICASERANGE) g_aRTUniUpperRanges[] =\n"
    10721126                  "{\n");
    10731127    RTUNICP i = 0;
     
    10951149            if (iStart < 0)
    10961150            {
    1097                 Stream1Printf("static const RTUNICP g_afRTUniUpper0x%06x[] = \n"
     1151                Stream1Printf("static const RTUNICP g_afRTUniUpper0x%06x[] =\n"
    10981152                              "{\n", i);
    10991153                iStart = i;
     
    11161170{
    11171171    Stream2Init();
    1118     Stream2Printf("const RTUNICASERANGE g_aRTUniLowerRanges[] =\n"
     1172    Stream2Printf("RT_DECL_DATA_CONST(const RTUNICASERANGE) g_aRTUniLowerRanges[] =\n"
    11191173                  "{\n");
    11201174    RTUNICP i = 0;
     
    11421196            if (iStart < 0)
    11431197            {
    1144                 Stream1Printf("static const RTUNICP g_afRTUniLower0x%06x[] = \n"
     1198                Stream1Printf("static const RTUNICP g_afRTUniLower0x%06x[] =\n"
    11451199                              "{\n", i);
    11461200                iStart = i;
     
    12021256            pszBaseDir = argv[argi];
    12031257        }
    1204         else if (   !strcmp(argv[argi], "-q")
    1205                  || !strcmp(argv[argi], "--quiet"))
    1206             g_fQuiet = true;
    12071258        else
    12081259        {
     
    12321283
    12331284    /*
    1234      * Print stuff.
     1285     * Produce output files.
    12351286     */
    1236     rc = PrintHeader(argv[0]);
    1237     if (rc)
    1238         return rc;
    1239     rc = PrintFlags();
    1240     if (rc)
    1241         return rc;
    1242     rc = PrintUpper();
    1243     if (rc)
    1244         return rc;
    1245     rc = PrintLower();
    1246     if (rc)
    1247         return rc;
     1287    rc = Stream1Init("unidata-flags.cpp");
     1288    if (!rc)
     1289        rc = PrintHeader(argv[0], pszBaseDir);
     1290    if (!rc)
     1291        rc = PrintFlags();
     1292
     1293    rc = Stream1Init("unidata-upper.cpp");
     1294    if (!rc)
     1295        rc = PrintHeader(argv[0], pszBaseDir);
     1296    if (!rc)
     1297        rc = PrintUpper();
     1298
     1299    rc = Stream1Init("unidata-lower.cpp");
     1300    if (!rc)
     1301        rc = PrintHeader(argv[0], pszBaseDir);
     1302    if (!rc)
     1303        rc = PrintLower();
     1304    if (!rc)
     1305        rc = Stream1Close();
    12481306
    12491307    /* done */
    1250     fflush(stdout);
    1251 
    12521308    return rc;
    12531309}
  • trunk/src/VBox/Runtime/common/string/utf-16.cpp

    r50795 r51770  
    171171
    172172
    173 RTDECL(int) RTUtf16ICmp(register PCRTUTF16 pwsz1, register PCRTUTF16 pwsz2)
    174 {
    175     if (pwsz1 == pwsz2)
    176         return 0;
    177     if (!pwsz1)
    178         return -1;
    179     if (!pwsz2)
    180         return 1;
    181 
    182     PCRTUTF16 pwsz1Start = pwsz1; /* keep it around in case we have to backtrack on a surrogate pair */
    183     for (;;)
    184     {
    185         register RTUTF16  wc1 = *pwsz1;
    186         register RTUTF16  wc2 = *pwsz2;
    187         register int     iDiff = wc1 - wc2;
    188         if (iDiff)
    189         {
    190             /* unless they are *both* surrogate pairs, there is no chance they'll be identical. */
    191             if (    wc1 < 0xd800
    192                 ||  wc2 < 0xd800
    193                 ||  wc1 > 0xdfff
    194                 ||  wc2 > 0xdfff)
    195             {
    196                 /* simple UCS-2 char */
    197                 iDiff = RTUniCpToUpper(wc1) - RTUniCpToUpper(wc2);
    198                 if (iDiff)
    199                     iDiff = RTUniCpToLower(wc1) - RTUniCpToLower(wc2);
    200             }
    201             else
    202             {
    203                 /* a damned pair */
    204                 RTUNICP uc1;
    205                 RTUNICP uc2;
    206                 if (wc1 >= 0xdc00)
    207                 {
    208                     if (pwsz1Start == pwsz1)
    209                         return iDiff;
    210                     uc1 = pwsz1[-1];
    211                     if (uc1 < 0xd800 || uc1 >= 0xdc00)
    212                         return iDiff;
    213                     uc1 = 0x10000 + (((uc1       & 0x3ff) << 10) | (wc1 & 0x3ff));
    214                     uc2 = 0x10000 + (((pwsz2[-1] & 0x3ff) << 10) | (wc2 & 0x3ff));
    215                 }
    216                 else
    217                 {
    218                     uc1 = *++pwsz1;
    219                     if (uc1 < 0xdc00 || uc1 >= 0xe000)
    220                         return iDiff;
    221                     uc1 = 0x10000 + (((wc1 & 0x3ff) << 10) | (uc1      & 0x3ff));
    222                     uc2 = 0x10000 + (((wc2 & 0x3ff) << 10) | (*++pwsz2 & 0x3ff));
    223                 }
    224                 iDiff = RTUniCpToUpper(uc1) - RTUniCpToUpper(uc2);
    225                 if (iDiff)
    226                     iDiff = RTUniCpToLower(uc1) - RTUniCpToLower(uc2); /* serious paranoia! */
    227             }
    228             if (iDiff)
    229                 return iDiff;
    230         }
    231         if (!wc1)
    232             return 0;
    233         pwsz1++;
    234         pwsz2++;
    235     }
    236 }
    237 RT_EXPORT_SYMBOL(RTUtf16ICmp);
    238 
    239 
    240 RTDECL(PRTUTF16) RTUtf16ToLower(PRTUTF16 pwsz)
    241 {
    242     PRTUTF16 pwc = pwsz;
    243     for (;;)
    244     {
    245         RTUTF16 wc = *pwc;
    246         if (!wc)
    247             break;
    248         if (wc < 0xd800 || wc >= 0xdc00)
    249         {
    250             RTUNICP ucFolded = RTUniCpToLower(wc);
    251             if (ucFolded < 0x10000)
    252                 *pwc++ = RTUniCpToLower(wc);
    253         }
    254         else
    255         {
    256             /* surrogate */
    257             RTUTF16 wc2 = pwc[1];
    258             if (wc2 >= 0xdc00 && wc2 <= 0xdfff)
    259             {
    260                 RTUNICP uc = 0x10000 + (((wc & 0x3ff) << 10) | (wc2 & 0x3ff));
    261                 RTUNICP ucFolded = RTUniCpToLower(uc);
    262                 if (uc != ucFolded && ucFolded >= 0x10000) /* we don't support shrinking the string */
    263                 {
    264                     uc -= 0x10000;
    265                     *pwc++ = 0xd800 | (uc >> 10);
    266                     *pwc++ = 0xdc00 | (uc & 0x3ff);
    267                 }
    268             }
    269             else /* invalid encoding. */
    270                 pwc++;
    271         }
    272     }
    273     return pwsz;
    274 }
    275 RT_EXPORT_SYMBOL(RTUtf16ToLower);
    276 
    277 
    278 RTDECL(PRTUTF16) RTUtf16ToUpper(PRTUTF16 pwsz)
    279 {
    280     PRTUTF16 pwc = pwsz;
    281     for (;;)
    282     {
    283         RTUTF16 wc = *pwc;
    284         if (!wc)
    285             break;
    286         if (wc < 0xd800 || wc >= 0xdc00)
    287             *pwc++ = RTUniCpToUpper(wc);
    288         else
    289         {
    290             /* surrogate */
    291             RTUTF16 wc2 = pwc[1];
    292             if (wc2 >= 0xdc00 && wc2 <= 0xdfff)
    293             {
    294                 RTUNICP uc = 0x10000 + (((wc & 0x3ff) << 10) | (wc2 & 0x3ff));
    295                 RTUNICP ucFolded = RTUniCpToUpper(uc);
    296                 if (uc != ucFolded && ucFolded >= 0x10000) /* we don't support shrinking the string */
    297                 {
    298                     uc -= 0x10000;
    299                     *pwc++ = 0xd800 | (uc >> 10);
    300                     *pwc++ = 0xdc00 | (uc & 0x3ff);
    301                 }
    302             }
    303             else /* invalid encoding. */
    304                 pwc++;
    305         }
    306     }
    307     return pwsz;
    308 }
    309 RT_EXPORT_SYMBOL(RTUtf16ToUpper);
    310 
    311 
    312173RTDECL(int) RTUtf16ValidateEncoding(PCRTUTF16 pwsz)
    313174{
     
    786647RT_EXPORT_SYMBOL(RTUtf16PutCpInternal);
    787648
    788 
    789 /**
    790  * Validate the UTF-16 encoding and calculates the length of a Latin1 encoding.
    791  *
    792  * @returns iprt status code.
    793  * @param   pwsz        The UTF-16 string.
    794  * @param   cwc         The max length of the UTF-16 string to consider.
    795  * @param   pcch        Where to store the length (excluding '\\0') of the Latin1 string. (cch == cb, btw)
    796  */
    797 static int rtUtf16CalcLatin1Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
    798 {
    799     int     rc = VINF_SUCCESS;
    800     size_t  cch = 0;
    801     while (cwc > 0)
    802     {
    803         RTUTF16 wc = *pwsz++; cwc--;
    804         if (!wc)
    805             break;
    806         else if (RT_LIKELY(wc < 0x100))
    807             ++cch;
    808         else
    809         {
    810             if (wc < 0xd800 || wc > 0xdfff)
    811             {
    812                 if (wc >= 0xfffe)
    813                 {
    814                     RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));
    815                     rc = VERR_CODE_POINT_ENDIAN_INDICATOR;
    816                     break;
    817                 }
    818             }
    819             else
    820             {
    821                 if (wc >= 0xdc00)
    822                 {
    823                     RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));
    824                     rc = VERR_INVALID_UTF16_ENCODING;
    825                     break;
    826                 }
    827                 if (cwc <= 0)
    828                 {
    829                     RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));
    830                     rc = VERR_INVALID_UTF16_ENCODING;
    831                     break;
    832                 }
    833                 wc = *pwsz++; cwc--;
    834                 if (wc < 0xdc00 || wc > 0xdfff)
    835                 {
    836                     RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));
    837                     rc = VERR_INVALID_UTF16_ENCODING;
    838                     break;
    839                 }
    840             }
    841 
    842             rc = VERR_NO_TRANSLATION;
    843             break;
    844         }
    845     }
    846 
    847     /* done */
    848     *pcch = cch;
    849     return rc;
    850 }
    851 
    852 
    853 /**
    854  * Recodes an valid UTF-16 string as Latin1.
    855  *
    856  * @returns iprt status code.
    857  * @param   pwsz        The UTF-16 string.
    858  * @param   cwc         The number of RTUTF16 characters to process from pwsz. The recoding
    859  *                      will stop when cwc or '\\0' is reached.
    860  * @param   psz         Where to store the Latin1 string.
    861  * @param   cch         The size of the Latin1 buffer, excluding the terminator.
    862  */
    863 static int rtUtf16RecodeAsLatin1(PCRTUTF16 pwsz, size_t cwc, char *psz, size_t cch)
    864 {
    865     unsigned char  *pch = (unsigned char *)psz;
    866     int             rc  = VINF_SUCCESS;
    867     while (cwc > 0)
    868     {
    869         RTUTF16 wc = *pwsz++; cwc--;
    870         if (!wc)
    871             break;
    872         if (RT_LIKELY(wc < 0x100))
    873         {
    874             if (RT_UNLIKELY(cch < 1))
    875             {
    876                 RTStrAssertMsgFailed(("Buffer overflow! 1\n"));
    877                 rc = VERR_BUFFER_OVERFLOW;
    878                 break;
    879             }
    880             cch--;
    881             *pch++ = (unsigned char)wc;
    882         }
    883         else
    884         {
    885             if (wc < 0xd800 || wc > 0xdfff)
    886             {
    887                 if (wc >= 0xfffe)
    888                 {
    889                     RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));
    890                     rc = VERR_CODE_POINT_ENDIAN_INDICATOR;
    891                     break;
    892                 }
    893             }
    894             else
    895             {
    896                 if (wc >= 0xdc00)
    897                 {
    898                     RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));
    899                     rc = VERR_INVALID_UTF16_ENCODING;
    900                     break;
    901                 }
    902                 if (cwc <= 0)
    903                 {
    904                     RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));
    905                     rc = VERR_INVALID_UTF16_ENCODING;
    906                     break;
    907                 }
    908                 RTUTF16 wc2 = *pwsz++; cwc--;
    909                 if (wc2 < 0xdc00 || wc2 > 0xdfff)
    910                 {
    911                     RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));
    912                     rc = VERR_INVALID_UTF16_ENCODING;
    913                     break;
    914                 }
    915             }
    916 
    917             rc = VERR_NO_TRANSLATION;
    918             break;
    919         }
    920     }
    921 
    922     /* done */
    923     *pch = '\0';
    924     return rc;
    925 }
    926 
    927 
    928 RTDECL(int)  RTUtf16ToLatin1Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag)
    929 {
    930     /*
    931      * Validate input.
    932      */
    933     Assert(VALID_PTR(ppszString));
    934     Assert(VALID_PTR(pwszString));
    935     *ppszString = NULL;
    936 
    937     /*
    938      * Validate the UTF-16 string and calculate the length of the UTF-8 encoding of it.
    939      */
    940     size_t cch;
    941     int rc = rtUtf16CalcLatin1Length(pwszString, RTSTR_MAX, &cch);
    942     if (RT_SUCCESS(rc))
    943     {
    944         /*
    945          * Allocate buffer and recode it.
    946          */
    947         char *pszResult = (char *)RTMemAllocTag(cch + 1, pszTag);
    948         if (pszResult)
    949         {
    950             rc = rtUtf16RecodeAsLatin1(pwszString, RTSTR_MAX, pszResult, cch);
    951             if (RT_SUCCESS(rc))
    952             {
    953                 *ppszString = pszResult;
    954                 return rc;
    955             }
    956 
    957             RTMemFree(pszResult);
    958         }
    959         else
    960             rc = VERR_NO_STR_MEMORY;
    961     }
    962     return rc;
    963 }
    964 RT_EXPORT_SYMBOL(RTUtf16ToLatin1Tag);
    965 
    966 
    967 RTDECL(int)  RTUtf16ToLatin1ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag)
    968 {
    969     /*
    970      * Validate input.
    971      */
    972     AssertPtr(pwszString);
    973     AssertPtr(ppsz);
    974     AssertPtrNull(pcch);
    975 
    976     /*
    977      * Validate the UTF-16 string and calculate the length of the Latin1 encoding of it.
    978      */
    979     size_t cchResult;
    980     int rc = rtUtf16CalcLatin1Length(pwszString, cwcString, &cchResult);
    981     if (RT_SUCCESS(rc))
    982     {
    983         if (pcch)
    984             *pcch = cchResult;
    985 
    986         /*
    987          * Check buffer size / Allocate buffer and recode it.
    988          */
    989         bool fShouldFree;
    990         char *pszResult;
    991         if (cch > 0 && *ppsz)
    992         {
    993             fShouldFree = false;
    994             if (cch <= cchResult)
    995                 return VERR_BUFFER_OVERFLOW;
    996             pszResult = *ppsz;
    997         }
    998         else
    999         {
    1000             *ppsz = NULL;
    1001             fShouldFree = true;
    1002             cch = RT_MAX(cch, cchResult + 1);
    1003             pszResult = (char *)RTMemAllocTag(cch, pszTag);
    1004         }
    1005         if (pszResult)
    1006         {
    1007             rc = rtUtf16RecodeAsLatin1(pwszString, cwcString, pszResult, cch - 1);
    1008             if (RT_SUCCESS(rc))
    1009             {
    1010                 *ppsz = pszResult;
    1011                 return rc;
    1012             }
    1013 
    1014             if (fShouldFree)
    1015                 RTMemFree(pszResult);
    1016         }
    1017         else
    1018             rc = VERR_NO_STR_MEMORY;
    1019     }
    1020     return rc;
    1021 }
    1022 RT_EXPORT_SYMBOL(RTUtf16ToLatin1ExTag);
    1023 
    1024 
    1025 RTDECL(size_t) RTUtf16CalcLatin1Len(PCRTUTF16 pwsz)
    1026 {
    1027     size_t cch;
    1028     int rc = rtUtf16CalcLatin1Length(pwsz, RTSTR_MAX, &cch);
    1029     return RT_SUCCESS(rc) ? cch : 0;
    1030 }
    1031 RT_EXPORT_SYMBOL(RTUtf16CalcLatin1Len);
    1032 
    1033 
    1034 RTDECL(int) RTUtf16CalcLatin1LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
    1035 {
    1036     size_t cch;
    1037     int rc = rtUtf16CalcLatin1Length(pwsz, cwc, &cch);
    1038     if (pcch)
    1039         *pcch = RT_SUCCESS(rc) ? cch : ~(size_t)0;
    1040     return rc;
    1041 }
    1042 RT_EXPORT_SYMBOL(RTUtf16CalcLatin1LenEx);
    1043 
    1044 
    1045 /**
    1046  * Calculates the UTF-16 length of a Latin1 string.  In fact this is just the
    1047  * original length, but the function saves us nasty comments to that effect
    1048  * all over the place.
    1049  *
    1050  * @returns IPRT status code.
    1051  * @param   psz     Pointer to the Latin1 string.
    1052  * @param   cch     The max length of the string. (btw cch = cb)
    1053  *                  Use RTSTR_MAX if all of the string is to be examined.s
    1054  * @param   pcwc    Where to store the length of the UTF-16 string as a number of RTUTF16 characters.
    1055  */
    1056 static int rtLatin1CalcUtf16Length(const char *psz, size_t cch, size_t *pcwc)
    1057 {
    1058     *pcwc = RTStrNLen(psz, cch);
    1059     return VINF_SUCCESS;
    1060 }
    1061 
    1062 
    1063 /**
    1064  * Recodes a Latin1 string as UTF-16.  This is just a case of expanding it to
    1065  * sixteen bits, as Unicode is a superset of Latin1.
    1066  *
    1067  * Since we know the input is valid, we do *not* perform length checks.
    1068  *
    1069  * @returns iprt status code.
    1070  * @param   psz     The Latin1 string to recode.
    1071  * @param   cch     The number of chars (the type char, so bytes if you like) to process of the Latin1 string.
    1072  *                  The recoding will stop when cch or '\\0' is reached. Pass RTSTR_MAX to process up to '\\0'.
    1073  * @param   pwsz    Where to store the UTF-16 string.
    1074  * @param   cwc     The number of RTUTF16 items the pwsz buffer can hold, excluding the terminator ('\\0').
    1075  */
    1076 static int rtLatin1RecodeAsUtf16(const char *psz, size_t cch, PRTUTF16 pwsz, size_t cwc)
    1077 {
    1078     int                     rc   = VINF_SUCCESS;
    1079     const unsigned char    *puch = (const unsigned char *)psz;
    1080     PRTUTF16                pwc  = pwsz;
    1081     while (cch-- > 0)
    1082     {
    1083         /* read the next char and check for terminator. */
    1084         const unsigned char uch = *puch;
    1085         if (!uch)
    1086             break;
    1087 
    1088         /* check for output overflow */
    1089         if (RT_UNLIKELY(cwc < 1))
    1090         {
    1091             rc = VERR_BUFFER_OVERFLOW;
    1092             break;
    1093         }
    1094 
    1095         /* expand the code point */
    1096         *pwc++ = uch;
    1097         cwc--;
    1098         puch++;
    1099     }
    1100 
    1101     /* done */
    1102     *pwc = '\0';
    1103     return rc;
    1104 }
    1105 
    1106 
    1107 RTDECL(int) RTLatin1ToUtf16Tag(const char *pszString, PRTUTF16 *ppwszString, const char *pszTag)
    1108 {
    1109     /*
    1110      * Validate input.
    1111      */
    1112     Assert(VALID_PTR(ppwszString));
    1113     Assert(VALID_PTR(pszString));
    1114     *ppwszString = NULL;
    1115 
    1116     /*
    1117      * Validate the input and calculate the length of the UTF-16 string.
    1118      */
    1119     size_t cwc;
    1120     int rc = rtLatin1CalcUtf16Length(pszString, RTSTR_MAX, &cwc);
    1121     if (RT_SUCCESS(rc))
    1122     {
    1123         /*
    1124          * Allocate buffer.
    1125          */
    1126         PRTUTF16 pwsz = (PRTUTF16)RTMemAllocTag((cwc + 1) * sizeof(RTUTF16), pszTag);
    1127         if (pwsz)
    1128         {
    1129             /*
    1130              * Encode the UTF-16 string.
    1131              */
    1132             rc = rtLatin1RecodeAsUtf16(pszString, RTSTR_MAX, pwsz, cwc);
    1133             if (RT_SUCCESS(rc))
    1134             {
    1135                 *ppwszString = pwsz;
    1136                 return rc;
    1137             }
    1138             RTMemFree(pwsz);
    1139         }
    1140         else
    1141             rc = VERR_NO_UTF16_MEMORY;
    1142     }
    1143     return rc;
    1144 }
    1145 RT_EXPORT_SYMBOL(RTLatin1ToUtf16Tag);
    1146 
    1147 
    1148 RTDECL(int)  RTLatin1ToUtf16ExTag(const char *pszString, size_t cchString,
    1149                                   PRTUTF16 *ppwsz, size_t cwc, size_t *pcwc, const char *pszTag)
    1150 {
    1151     /*
    1152      * Validate input.
    1153      */
    1154     Assert(VALID_PTR(pszString));
    1155     Assert(VALID_PTR(ppwsz));
    1156     Assert(!pcwc || VALID_PTR(pcwc));
    1157 
    1158     /*
    1159      * Validate the input and calculate the length of the UTF-16 string.
    1160      */
    1161     size_t cwcResult;
    1162     int rc = rtLatin1CalcUtf16Length(pszString, cchString, &cwcResult);
    1163     if (RT_SUCCESS(rc))
    1164     {
    1165         if (pcwc)
    1166             *pcwc = cwcResult;
    1167 
    1168         /*
    1169          * Check buffer size / Allocate buffer.
    1170          */
    1171         bool fShouldFree;
    1172         PRTUTF16 pwszResult;
    1173         if (cwc > 0 && *ppwsz)
    1174         {
    1175             fShouldFree = false;
    1176             if (cwc <= cwcResult)
    1177                 return VERR_BUFFER_OVERFLOW;
    1178             pwszResult = *ppwsz;
    1179         }
    1180         else
    1181         {
    1182             *ppwsz = NULL;
    1183             fShouldFree = true;
    1184             cwc = RT_MAX(cwcResult + 1, cwc);
    1185             pwszResult = (PRTUTF16)RTMemAllocTag(cwc * sizeof(RTUTF16), pszTag);
    1186         }
    1187         if (pwszResult)
    1188         {
    1189             /*
    1190              * Encode the UTF-16 string.
    1191              */
    1192             rc = rtLatin1RecodeAsUtf16(pszString, cchString, pwszResult, cwc - 1);
    1193             if (RT_SUCCESS(rc))
    1194             {
    1195                 *ppwsz = pwszResult;
    1196                 return rc;
    1197             }
    1198             if (fShouldFree)
    1199                 RTMemFree(pwszResult);
    1200         }
    1201         else
    1202             rc = VERR_NO_UTF16_MEMORY;
    1203     }
    1204     return rc;
    1205 }
    1206 RT_EXPORT_SYMBOL(RTLatin1ToUtf16ExTag);
    1207 
    1208 
    1209 RTDECL(size_t) RTLatin1CalcUtf16Len(const char *psz)
    1210 {
    1211     size_t cwc;
    1212     int rc = rtLatin1CalcUtf16Length(psz, RTSTR_MAX, &cwc);
    1213     return RT_SUCCESS(rc) ? cwc : 0;
    1214 }
    1215 RT_EXPORT_SYMBOL(RTLatin1CalcUtf16Len);
    1216 
    1217 
    1218 RTDECL(int) RTLatin1CalcUtf16LenEx(const char *psz, size_t cch, size_t *pcwc)
    1219 {
    1220     size_t cwc;
    1221     int rc = rtLatin1CalcUtf16Length(psz, cch, &cwc);
    1222     if (pcwc)
    1223         *pcwc = RT_SUCCESS(rc) ? cwc : ~(size_t)0;
    1224     return rc;
    1225 }
    1226 RT_EXPORT_SYMBOL(RTLatin1CalcUtf16LenEx);
  • trunk/src/VBox/Runtime/common/string/utf-8-case.cpp

    r48935 r51770  
    11/* $Id$ */
    22/** @file
    3  * IPRT - UTF-8 Case Sensitivity and Folding.
     3 * IPRT - UTF-8 Case Sensitivity and Folding, Part 1.
    44 */
    55
     
    339339RT_EXPORT_SYMBOL(RTStrToUpper);
    340340
    341 
    342 RTDECL(bool) RTStrIsCaseFoldable(const char *psz)
    343 {
    344     /*
    345      * Loop the code points in the string, checking them one by one until we
    346      * find something that can be folded.
    347      */
    348     RTUNICP uc;
    349     do
    350     {
    351         int rc = RTStrGetCpEx(&psz, &uc);
    352         if (RT_SUCCESS(rc))
    353         {
    354             if (RTUniCpIsFoldable(uc))
    355                 return true;
    356         }
    357         else
    358         {
    359             /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
    360             AssertRC(rc);
    361         }
    362     } while (uc != 0);
    363 
    364     return false;
    365 }
    366 RT_EXPORT_SYMBOL(RTStrIsCaseFoldable);
    367 
    368 
    369 RTDECL(bool) RTStrIsUpperCased(const char *psz)
    370 {
    371     /*
    372      * Check that there are no lower case chars in the string.
    373      */
    374     RTUNICP uc;
    375     do
    376     {
    377         int rc = RTStrGetCpEx(&psz, &uc);
    378         if (RT_SUCCESS(rc))
    379         {
    380             if (RTUniCpIsLower(uc))
    381                 return false;
    382         }
    383         else
    384         {
    385             /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
    386             AssertRC(rc);
    387         }
    388     } while (uc != 0);
    389 
    390     return true;
    391 }
    392 RT_EXPORT_SYMBOL(RTStrIsUpperCased);
    393 
    394 
    395 RTDECL(bool) RTStrIsLowerCased(const char *psz)
    396 {
    397     /*
    398      * Check that there are no lower case chars in the string.
    399      */
    400     RTUNICP uc;
    401     do
    402     {
    403         int rc = RTStrGetCpEx(&psz, &uc);
    404         if (RT_SUCCESS(rc))
    405         {
    406             if (RTUniCpIsUpper(uc))
    407                 return false;
    408         }
    409         else
    410         {
    411             /* bad encoding, just skip it quietly (uc == RTUNICP_INVALID (!= 0)). */
    412             AssertRC(rc);
    413         }
    414     } while (uc != 0);
    415 
    416     return true;
    417 }
    418 RT_EXPORT_SYMBOL(RTStrIsLowerCased);
    419 
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette