LONG
Win32U_RegCreateKeyEx(HKEY keyName,                      // IN:
                      LPCSTR subKey,                     // IN:
                      DWORD reserved,                    // IN: reserved
                      LPCSTR className,                  // IN:
                      DWORD options,                     // IN:
                      REGSAM samDesired,                 // IN:
                      LPSECURITY_ATTRIBUTES attributes,  // IN:
                      HKEY *resultHandle,                // OUT:
                      DWORD *disposition)                // OUT: optional
{
   LONG ret;
   utf16_t *subKeyW;
   utf16_t *classNameW;

   ASSERT(subKey);              /* subKey must not be NULL */

   subKeyW = Unicode_GetAllocUTF16(subKey);
   classNameW = Unicode_GetAllocUTF16(className);

   ret = RegCreateKeyExW(keyName, subKeyW, reserved, classNameW, options,
                         samDesired, attributes, resultHandle, disposition);

   free(classNameW);
   free(subKeyW);

   return ret;
}
LONG
Win32U_RegLoadKey(HKEY keyName,    // IN:
                  LPCSTR subKey,   // IN:
                  LPCSTR regFile)  // IN:
{
   LONG ret;
   utf16_t *subKeyW = Unicode_GetAllocUTF16(subKey);
   utf16_t *regFileW = Unicode_GetAllocUTF16(regFile);

   ret = RegLoadKeyW(keyName, subKeyW, regFileW);
   free(subKeyW);
   free(regFileW);

   return ret;
}
LONG
Win32U_RegSetValueEx(HKEY keyName,      // IN:
                     LPCSTR valueName,  // IN: can be NULL
                     DWORD reserved,    // IN: reserved
                     DWORD type,        // IN:
                     const BYTE* data,  // IN, can be NULL
                     DWORD cbData)      // IN:
{
   LONG ret;
   utf16_t *valueNameW = Unicode_GetAllocUTF16(valueName);
   LPBYTE dataW;
   size_t cbDataW;

   switch (type) {
   case REG_SZ:
   case REG_EXPAND_SZ:
   case REG_MULTI_SZ:
      CodeSet_Utf8ToUtf16le(data, cbData, (char **)&dataW, &cbDataW);
      break;

   default: /* Other types of registry values pass-thru as- */
      dataW = (LPBYTE) data;
      cbDataW = cbData;
   }

   ret = RegSetValueExW(keyName, valueNameW, reserved, type, dataW, cbDataW);

   if (type == REG_SZ || type == REG_EXPAND_SZ || type == REG_MULTI_SZ) {
      free(dataW);
   }
   free(valueNameW);

   return ret;
}
LONG
Win32U_RegDeleteValue(HKEY keyName,      // IN:
                      LPCSTR valueName)  // IN:
{
   LONG ret;
   utf16_t *valueNameW = Unicode_GetAllocUTF16(valueName);

   ret = RegDeleteValueW(keyName, valueNameW);
   free(valueNameW);

   return ret;
}
LONG
Win32U_RegUnLoadKey(HKEY keyName,   // IN:
                    LPCSTR subKey)  // IN:
{
   LONG ret;
   utf16_t *subKeyW = Unicode_GetAllocUTF16(subKey);

   ret = RegUnLoadKeyW(keyName, subKeyW);
   free(subKeyW);

   return ret;
}
Ejemplo n.º 6
0
VixError
VixToolsEnvironToEnvBlock(char const * const *environ,    // IN: UTF-8
                          wchar_t **envBlock)             // OUT
{
   VixError err;
   DynBuf buf;
   Bool res;
   static const wchar_t nullTerm[] = { L'\0', L'\0' };

   DynBuf_Init(&buf);

   if ((NULL == environ) || (NULL == envBlock)) {
      err = VIX_E_FAIL;
      goto abort;
   }

   *envBlock = NULL;

   while (NULL != *environ) {
      wchar_t *envVar = Unicode_GetAllocUTF16(*environ);

      res = DynBuf_Append(&buf, envVar,
                          (wcslen(envVar) + 1) * sizeof(*envVar));
      free(envVar);
      if (!res) {
         err = VIX_E_OUT_OF_MEMORY;
         goto abort;
      }
      environ++;
   }

   /*
    * Append two null characters at the end. This adds an extra (third) null
    * if there was at least one environment variable (since there already
    * is one after the last string) but we need both if there were no
    * environment variables in the input array. I'll waste two bytes to
    * keep the code a little simpler.
    */
   res = DynBuf_Append(&buf, nullTerm, sizeof nullTerm);
   if (!res) {
      err = VIX_E_OUT_OF_MEMORY;
      goto abort;
   }

   *envBlock = DynBuf_Detach(&buf);
   err = VIX_OK;

abort:
   DynBuf_Destroy(&buf);

   return err;
}
LONG
Win32U_RegRestoreKey(HKEY keyName,    // IN:
                     LPCSTR keyFile,  // IN:
                     DWORD flags)     // IN:
{
   LONG ret;
   utf16_t *keyFileW = Unicode_GetAllocUTF16(keyFile);

   ret = RegRestoreKeyW(keyName, keyFileW, flags);
   free(keyFileW);

   return ret;
}
LONG
Win32U_RegSaveKey(HKEY keyName,                // IN:
                  LPCSTR keyFile,              // IN:
                  LPSECURITY_ATTRIBUTES attr)  // IN:
{
   LONG ret;
   utf16_t *keyFileW = Unicode_GetAllocUTF16(keyFile);

   ret = RegSaveKeyW(keyName, keyFileW, attr);
   free(keyFileW);

   return ret;
}
LONG
Win32U_RegOpenKeyEx(HKEY keyName,        // IN:
                    LPCSTR subKey,       // IN: can be NULL
                    DWORD options,       // IN: reserved
                    REGSAM samDesired,   // IN:
                    HKEY *resultHandle)  // OUT:
{
   LONG ret;
   utf16_t *subKeyW;

   subKeyW = Unicode_GetAllocUTF16(subKey);

   ret = RegOpenKeyExW(keyName, subKeyW, options, samDesired, resultHandle);

   free(subKeyW);

   return ret;
}
Ejemplo n.º 10
0
int
Unicode_CompareRange(ConstUnicode str1,       // IN
                     UnicodeIndex str1Start,  // IN
                     UnicodeIndex str1Length, // IN
                     ConstUnicode str2,       // IN
                     UnicodeIndex str2Start,  // IN
                     UnicodeIndex str2Length, // IN
                     Bool ignoreCase)         // IN
{
   int result = -1;
   Unicode substr1 = NULL;
   Unicode substr2 = NULL;
   utf16_t *substr1UTF16 = NULL;
   utf16_t *substr2UTF16 = NULL;
   UnicodeIndex i = 0;
   UnicodeIndex utf16Index;
   utf16_t codeUnit1;
   utf16_t codeUnit2;
   uint32 codePoint1;
   uint32 codePoint2;

   UnicodePinIndices(str1, &str1Start, &str1Length);
   UnicodePinIndices(str2, &str2Start, &str2Length);

   /*
    * TODO: Allocating substrings is a performance hit.  We should do
    * this search in-place.  (However, searching UTF-8 requires tender loving
    * care, and it's just easier to search UTF-16.)
    */
   substr1 = Unicode_Substr(str1, str1Start, str1Length);
   if (!substr1) {
      goto out;
   }

   substr2 = Unicode_Substr(str2, str2Start, str2Length);
   if (!substr2) {
      goto out;
   }

   /*
    * XXX TODO: Need to normalize the incoming strings to NFC or NFD.
    */
   substr1UTF16 = Unicode_GetAllocUTF16(substr1);
   if (!substr1UTF16) {
      goto out;
   }

   substr2UTF16 = Unicode_GetAllocUTF16(substr2);
   if (!substr2UTF16) {
      goto out;
   }

   /*
    * TODO: This is the naive string search algorithm, which is
    * O(n * m).  We can do better with KMP or Boyer-Moore if this
    * proves to be a bottleneck.
    */
   while (TRUE) {
      codeUnit1 = *(substr1UTF16 + i);
      codeUnit2 = *(substr2UTF16 + i);

      /*
       * TODO: Simple case folding doesn't handle the situation where
       * more than one code unit is needed to store the result of the
       * case folding.
       *
       * This means that German "straBe" (where B = sharp S, U+00DF)
       * will not match "STRASSE", even though the two strings are the
       * same.
       */
      if (ignoreCase) {
         codeUnit1 = UnicodeSimpleCaseFold(codeUnit1);
         codeUnit2 = UnicodeSimpleCaseFold(codeUnit2);
      }

      if (codeUnit1 != codeUnit2) {
         break;
      }

      if (codeUnit1 == 0) {
         // End of both strings reached: strings are equal.
         result = 0;
         goto out;
      }

      i++;
   }

   /*
    * The two UTF-16 code units differ.  If they're the first code unit
    * of a surrogate pair (for Unicode values past U+FFFF), decode the
    * surrogate pair into a full Unicode code point.
    */
   if (U16_IS_SURROGATE(codeUnit1)) {
      ssize_t substrUTF16Len = Unicode_UTF16Strlen(substr1UTF16);

      // U16_NEXT modifies the index, so let it work on a copy.
      utf16Index = i;

      // Decode the surrogate if needed.
      U16_NEXT(substr1UTF16, utf16Index, substrUTF16Len, codePoint1);
   } else {
      // Not a surrogate?  Then the code point value is the code unit.
      codePoint1 = codeUnit1;
   }

   if (U16_IS_SURROGATE(codeUnit2)) {
      ssize_t substrUTF16Len = Unicode_UTF16Strlen(substr2UTF16);

      utf16Index = i;
      U16_NEXT(substr2UTF16, utf16Index, substrUTF16Len, codePoint2);
   } else {
      codePoint2 = codeUnit2;
   }

   if (codePoint1 < codePoint2) {
      result = -1;
   } else if (codePoint1 > codePoint2) {
      result = 1;
   } else {
      // If we hit the end of the string, we've already gone to 'out'.
      NOT_REACHED();
   }

  out:
   free(substr1UTF16);
   free(substr2UTF16);

   Unicode_Free(substr1);
   Unicode_Free(substr2);

   return result;
}
LONG
Win32U_AllocRegQueryValueEx(HKEY keyName,      // IN:
                            LPCSTR valueName,  // IN: can be NULL
                            LPDWORD reserved,  // IN: reserved
                            LPDWORD type,      // OUT/OPT: can be NULL
                            LPBYTE *data,      // OUT:
                            LPDWORD dataSize)  // OUT:
{
   LONG ret;
   utf16_t *valueNameW = Unicode_GetAllocUTF16(valueName);
   DWORD valueType;
   char *rawData = NULL;
   DWORD rawDataSize = 0;
   DWORD bufferSize = 0;

   ASSERT(data);
   ASSERT(dataSize);
   ASSERT(reserved == NULL);

   *data = NULL;
   *dataSize = 0;

   ret = RegQueryValueExW(keyName, valueNameW, reserved, NULL, NULL,
                          &bufferSize);
   if (ret != ERROR_SUCCESS || bufferSize == 0) {
      bufferSize = 256;
   }

   /*
    * This loops with a growing buffer because:
    * * The registry value could be modified between calls to
    *   RegQueryValueExW.
    * * RegQueryValueExW will never tell us how large a buffer we need
    *   for HKEY_PERFORMANCE_DATA values.
    */

   while (TRUE) {
      rawData = Util_SafeRealloc(rawData, bufferSize);
      rawDataSize = bufferSize;
      ret = RegQueryValueExW(keyName, valueNameW, reserved, &valueType,
                             rawData, &rawDataSize);
      if (ERROR_MORE_DATA != ret) {
         break;
      }
      bufferSize *= 2;
   }

   if (ERROR_SUCCESS != ret) {
      goto exit;
   }

   ASSERT(rawDataSize <= bufferSize);

   /* Write back the data */
   switch (valueType) {
      /* Do UTF-16->UTF-8 conversion for string types. */
      case REG_SZ:
      case REG_MULTI_SZ:
      case REG_EXPAND_SZ:
      {
         size_t sizeOut;

         if (!CodeSet_Utf16leToUtf8(rawData, rawDataSize, data, &sizeOut)) {
            /*
             * Someone may not have set the right data size.  Let's try
             * to convert up to NUL if one is found.
             */

            DWORD lenInBytes = rawDataSize;
            const utf16_t *p1 = (utf16_t*)rawData;
            const utf16_t *p2 = (utf16_t*)&rawData[rawDataSize];
            
            if (valueType == REG_MULTI_SZ) {    /* look for four NUL bytes */
               while (p1 < p2) {
                  for (; *p1 != 0 && p1 < p2; p1++) {
                  }
                  p1++;
                  if (p1 < p2 && *p1 == 0) {
                     lenInBytes = (char *)p1 - rawData + 2;
                     break;
                  }
               }
            } else {
               for (; *p1 != 0 && p1 < p2; p1++) {
               }
               if (p1 < p2) {
                  lenInBytes = (char *)p1 - rawData + 2;
               }
            }

            ASSERT(lenInBytes <= rawDataSize);
            ASSERT(lenInBytes % 2 == 0);

            if (lenInBytes >= rawDataSize ||
                !CodeSet_Utf16leToUtf8(rawData, lenInBytes, data, &sizeOut)) {
               ret = ERROR_INVALID_DATA;
               goto exit;
            }
         }
         *dataSize = sizeOut;
         break;
      }
      default:
         /* Shrink the buffer down to what we actually used. */
         *data = Util_SafeRealloc(rawData, rawDataSize);
         *dataSize = rawDataSize;
         rawData = NULL;
         break;
   }

   /* Write back the type information if asked for */
   if (type) {
      *type = valueType;
   }

exit:
   free(valueNameW);
   free(rawData);

   return ret;
}
LONG
Win32U_RegQueryValueEx(HKEY keyName,      // IN:
                       LPCSTR valueName,  // IN: can be NULL
                       LPDWORD reserved,  // IN: reserved
                       LPDWORD type,      // OUT: can be NULL
                       LPBYTE data,       // OUT: can be NULL
                       LPDWORD dataSize)  // IN/OUT: can be NULL if data is NULL
{
   LONG ret;
   utf16_t *valueNameW = Unicode_GetAllocUTF16(valueName);
   DWORD valueType;

   char *dataTemp = NULL;
   DWORD dataSizeTemp = 0;

   ASSERT(reserved == NULL);

   if (data) {
      ASSERT(dataSize != NULL);
      dataSizeTemp = *dataSize * 2;

      /*
       * We always allocate one extra word of space, so that we can write a
       * null character to the end of the data returned from the registry.
       * This protects us from crashing in the Win32UWriteBackRegData function
       * if the caller is attempting to get a value of type REG_SZ, and the
       * data is the registry is not properly null terminated.
       */

      dataTemp = Util_SafeMalloc(dataSizeTemp + sizeof L'\0');
   }

   ret = RegQueryValueExW(keyName, valueNameW, reserved, &valueType,
                          dataTemp, &dataSizeTemp);

   if (dataTemp && ERROR_SUCCESS == ret && REG_SZ == valueType) {
      /*
       * Append a null word to the returned data, in case the value is not
       * null terminated in the registry.
       */

      *((PWCHAR) (dataTemp + dataSizeTemp)) = L'\0';

      /*
       * Get the length of the string. The registry doesn't enforce any rules
       * on the consistency of the data written into a value of REG_SZ type,
       * so a poorly written application can end up writing bytes _after_ the
       * NULL character in the string (e.g., because of an off-by-one error).
       *
       * If we try to convert those extra bytes to utf8, the conversion will
       * typically fail and we get a Panic() (cf. bug 352057). Getting the
       * string length here prevents us from crashing in this (fairly common)
       * case, and cuts down on the number of support calls.
       */

      dataSizeTemp = Unicode_LengthInBytes(dataTemp, STRING_ENCODING_UTF16);
   }

   ret = Win32UWriteBackRegData(dataTemp, dataSizeTemp, data, dataSize,
                                valueType, ret);

   /* Write back the type information if asked for */
   if (type) {
      *type = valueType;
   }

   free(valueNameW);
   free(dataTemp);

   return ret;
}