Example #1
0
int
Str_Vsnprintf(char *str,          // OUT
              size_t size,        // IN
              const char *format, // IN
              va_list ap)         // IN
{
   int retval;

   ASSERT(str != NULL);
   ASSERT(format != NULL);

#ifndef HAS_BSD_PRINTF
   retval = vsnprintf(str, size, format, ap);
#elif defined __linux__
   {
      va_list aq;

      va_copy(aq, ap);
      retval = bsd_vsnprintf(&str, size, format, aq);
      va_end(aq);
   }
#else
   retval = bsd_vsnprintf(&str, size, format, ap);
#endif

   /*
    * Linux glibc 2.0.x returns -1 and null terminates (which we shouldn't
    * be linking against), but glibc 2.1.x follows c99 and returns
    * characters that would have been written.
    *
    * In the case of Win32 and !HAS_BSD_PRINTF, we are using
    * _vsnprintf(), which returns -1 on overflow, returns size
    * when result fits exactly, and does not null terminate in
    * those cases.
    */

   if ((retval < 0 || retval >= size) && size > 0) {
      /* Find UTF-8 code point boundary and place NUL termination there */
      int trunc = CodeSet_Utf8FindCodePointBoundary(str, size - 1);
      str[trunc] = '\0';
   }
   if (retval >= size) {
      return -1;
   }
   return retval;
}
Bool
Unicode_CopyBytes(void *destBuffer,        // OUT
                  ConstUnicode srcBuffer,  // IN
                  size_t maxLengthInBytes, // IN
                  size_t *retLength,       // OUT
                  StringEncoding encoding) // IN
{
   const char *utf8Str = (const char *)srcBuffer;
   Bool success = FALSE;
   size_t copyBytes = 0;

   encoding = Unicode_ResolveEncoding(encoding);

   switch (encoding) {
   case STRING_ENCODING_US_ASCII:
      if (!UnicodeSanityCheck(utf8Str, -1, encoding)) {
	 break;
      }
      // fall through
   case STRING_ENCODING_UTF8:
      {
         size_t len = strlen(utf8Str);
         copyBytes = MIN(len, maxLengthInBytes - 1);
         memcpy(destBuffer, utf8Str, copyBytes);

         /*
          * If we truncated, force a null termination in a UTF-8 safe
          * manner.
          */
         if (copyBytes >= len) {
	    success = TRUE;
	 } else {
            if (encoding == STRING_ENCODING_UTF8) {
               copyBytes =
                  CodeSet_Utf8FindCodePointBoundary(destBuffer, copyBytes);
            }
         }

         ((char*)destBuffer)[copyBytes] = '\0';
      }
      break;
   case STRING_ENCODING_UTF16_LE:
      {
         char *utf16Buf;
         size_t utf16BufLen;

         if (!CodeSet_Utf8ToUtf16le(utf8Str,
                                    strlen(utf8Str),
                                    &utf16Buf,
                                    &utf16BufLen)) {
	    // input should be valid UTF-8, no conversion error possible
	    ASSERT_MEM_ALLOC(FALSE);
            break;
         }
         copyBytes = MIN(utf16BufLen, maxLengthInBytes - 2);
         memcpy(destBuffer, utf16Buf, copyBytes);
         copyBytes = CodeSet_Utf16FindCodePointBoundary(destBuffer, copyBytes);
         ((utf16_t*)destBuffer)[copyBytes / 2] = 0;
         free(utf16Buf);

         if (copyBytes >= utf16BufLen) {
            success = TRUE;
         }

         break;
      }
   default:
      {
         char *currentBuf;
         size_t currentBufSize;

	 if (!CodeSet_GenericToGeneric("UTF-8", utf8Str, strlen(utf8Str),
				       Unicode_EncodingEnumToName(encoding),
				       CSGTG_NORMAL,
				       &currentBuf, &currentBufSize)) {
	    // XXX can't distinguish error cause
	    break;
	 }
         copyBytes = MIN(currentBufSize, maxLengthInBytes - 1);
         memcpy(destBuffer, currentBuf, copyBytes);
         free(currentBuf);

         /* 
          * XXX this isn't quite correct, we still need to truncate on
          * a code point boundary, based on the current encoding type,
          * rather than just null terminate blindly.
          */

         ((char*)destBuffer)[copyBytes] = 0;

         if (copyBytes >= currentBufSize) {
            success = TRUE;
         }
      }
      break;
   }

   if (retLength) {
      *retLength = copyBytes;
   }
   return success;
}
Example #3
0
const char *
Err_Errno2String(Err_Number errorNumber) // IN
{
   HashTable *numTable;
   HashTable *ptrTable;
   ErrInfo *info;
   ErrInfo *oldInfo;
   Err_Number oldErrno = Err_Errno();

   ASSERT(errorNumber != ERR_INVALID);

   /*
    * Look up the error in numTable.
    * Or insert it if it's not there.
    */

   numTable = NUMTABLE();
   if (!HashTable_Lookup(numTable, (void *) (uintptr_t) errorNumber,
			 (void **) &info)) {
      char buf[2048];
      const char *p;
      size_t n;

      /*
       * Convert number to string and build the info structure.
       */

      p = ErrErrno2String(errorNumber, buf, sizeof buf);

      info = Util_SafeMalloc(sizeof *info);
      info->number = errorNumber;
      info->string = Util_SafeStrdup(p);

      /*
       * To be safe, make sure the end of the string is at
       * a UTF-8 boundary, but we can only do this when the
       * string is in our buffer (it may not be).
       */

      n = strlen(info->string);
      n = CodeSet_Utf8FindCodePointBoundary(info->string, n);
      info->string[n] = '\0';

      /*
       * Try to insert new info into numTable.
       * If that fails, then we must have lost out to someone else.
       * Use theirs in that case.
       */

      oldInfo = HashTable_LookupOrInsert(numTable,
				         (void *) (uintptr_t) errorNumber,
				         info);
      if (oldInfo != info) {
	 ASSERT(oldInfo->number == info->number);
	 ASSERT(Str_Strcmp(oldInfo->string, info->string) == 0);
	 free(info->string);
	 free(info);
	 info = oldInfo;
      }
   }

   /*
    * Try to insert info into ptrTable.
    * We need to do it even if we didn't create this entry,
    * because we may get here before the other guy (who created
    * the entry and inserted it into numTable).
    */

   ptrTable = PTRTABLE();
   oldInfo = HashTable_LookupOrInsert(ptrTable, info->string, info);
   ASSERT(oldInfo == info);

#if defined VMX86_DEBUG && defined __linux__
   {
      HashTable *strTable = STRTABLE();
      ErrInfo *i = HashTable_LookupOrInsert(strTable, info->string, info);
      ASSERT(i == info);
   }
#endif

   Err_SetErrno(oldErrno);
   return info->string;
}