diff --git a/toolkit/components/osfile/osfileutils.cpp b/toolkit/components/osfile/osfileutils.cpp new file mode 100644 index 000000000000..0950924c76f5 --- /dev/null +++ b/toolkit/components/osfile/osfileutils.cpp @@ -0,0 +1,194 @@ + +#include "mozilla/Scoped.h" + +#include "osfileutils.h" +#include "nsICharsetConverterManager.h" +#include "nsServiceManagerUtils.h" +#include "nsCOMPtr.h" +#include "nsCRTGlue.h" + +// Utilities for handling errors +namespace { + +#if defined(XP_WIN) +#include + +/** + * Set the OS-specific error to inform the OS that + * the last operation failed because it is not supported. + */ +void error_not_supported() { + SetLastError(ERROR_NOT_SUPPORTED); +} + +/** + * Set the OS-specific error to inform the OS that + * the last operation failed because of an invalid + * argument. + */ +void error_invalid_argument() { + SetLastError(ERROR_INVALID_DATA); +} + +/** + * Set the OS-specific error to inform the OS that + * the last operation failed because of insufficient + * memory. + */ +void error_no_memory() { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); +} + +#else + +#include "errno.h" + +/** + * Set the OS-specific error to inform the OS that + * the last operation failed because it is not supported. + */ +void error_not_supported() { + errno = ENOTSUP; +} + +/** + * Set the OS-specific error to inform the OS that + * the last operation failed because of an invalid + * argument. + */ +void error_invalid_argument() { + errno = EINVAL; +} + +/** + * Set the OS-specific error to inform the OS that + * the last operation failed because of insufficient + * memory. + */ +void error_no_memory() { + errno = ENOMEM; +} + +#endif // defined(XP_WIN) + +} + + +extern "C" { + +// Memory utilities + +MOZ_EXPORT_API(void) osfile_ns_free(void* buf) { + NS_Free(buf); +} + +// Unicode utilities + +MOZ_EXPORT_API(PRUnichar*) osfile_wstrdup(PRUnichar* string) { + return NS_strdup(string); +} + +MOZ_EXPORT_API(PRUnichar*) osfile_DecodeAll( + const char* aEncoding, + const char* aSource, + const int32_t aBytesToDecode) +{ + if (!aEncoding || !aSource) { + error_invalid_argument(); + return nsnull; + } + + nsresult rv; + nsCOMPtr manager = + do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + error_not_supported(); + return nsnull; + } + + nsCOMPtr decoder; + rv = manager->GetUnicodeDecoder(aEncoding, getter_AddRefs(decoder)); + if (NS_FAILED(rv)) { + error_invalid_argument(); + return nsnull; + } + + // Compute an upper bound to the number of chars, allocate buffer + + int32_t srcBytes = aBytesToDecode; + int32_t upperBoundChars = 0; + rv = decoder->GetMaxLength(aSource, srcBytes, &upperBoundChars); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + int32_t bufSize = (upperBoundChars + 1) * sizeof (PRUnichar); + + mozilla::ScopedFreePtr dest((PRUnichar*)NS_Alloc(bufSize)); + if (dest.get() == nsnull) { + error_no_memory(); + return nsnull; + } + + // Convert, add trailing \0 + + rv = decoder->Convert(aSource, &srcBytes, dest.rwget(), &upperBoundChars); + if (NS_FAILED(rv)) { + error_invalid_argument(); + return nsnull; + } + + dest.rwget()[upperBoundChars] = '\0'; + + return dest.forget(); +} + +MOZ_EXPORT_API(char*) osfile_EncodeAll( + const char* aEncoding, + const PRUnichar* aSource, + int32_t* aBytesProduced) +{ + if (!aEncoding || !aSource || !aBytesProduced) { + error_invalid_argument(); + return nsnull; + } + + nsresult rv; + nsCOMPtr manager = + do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + error_not_supported(); + return nsnull; + } + + nsCOMPtr encoder; + rv = manager->GetUnicodeEncoder(aEncoding, getter_AddRefs(encoder)); + if (NS_FAILED(rv)) { + error_invalid_argument(); + return nsnull; + } + + int32_t srcChars = NS_strlen(aSource); + + int32_t upperBoundBytes = 0; + rv = encoder->GetMaxLength(aSource, srcChars, &upperBoundBytes); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + printf_stderr("Encoding %d chars into at up to %d bytes\n", srcChars, upperBoundBytes); + int32_t bufSize = upperBoundBytes; + mozilla::ScopedFreePtr dest((char*)NS_Alloc(bufSize)); + + if (dest.get() == nsnull) { + error_no_memory(); + return nsnull; + } + + rv = encoder->Convert(aSource, &srcChars, dest.rwget(), &upperBoundBytes); + if (NS_FAILED(rv)) { + error_invalid_argument(); + return nsnull; + } + + *aBytesProduced = upperBoundBytes; + return dest.forget(); +} + +} // extern "C" diff --git a/toolkit/components/osfile/osfileutils.h b/toolkit/components/osfile/osfileutils.h new file mode 100644 index 000000000000..fe3be9a5d852 --- /dev/null +++ b/toolkit/components/osfile/osfileutils.h @@ -0,0 +1,65 @@ +#ifndef mozilla_osfileutils_h__ +#define mozilla_osfileutils_h__ + +#include "mozilla/Types.h" +#include "nsIUnicodeDecoder.h" +#include "nsIUnicodeEncoder.h" + +extern "C" { + +// Memory utilities + +/** + * As |NS_Free|, but exported. + */ +MOZ_EXPORT_API(void) osfile_ns_free(void* buf); + +// Unicode utilities + +/** + * Duplicate a Unicode string, as per wpcpy/StrDupW. + * + * @param source A well-formed, nul-terminated, Unicode string. + * + * @return Either |NULL| if there was not enough memory to copy the + * string, or a new string with the same contents as |source|. + * Memory MUST be released with |osfile_ns_free|. + */ +MOZ_EXPORT_API(PRUnichar*) osfile_wstrdup(PRUnichar* source); + +/** + * Decode a nul-terminated C string into a Unicode string. + * + * @param aEncoding The encoding to use. + * @param aSource The C string to decode. + * @param aBytesToDecode The number of bytes to decode from |aSource|. + * + * @return null in case of error, otherwise a sequence of Unicode + * chars, representing |aSource|. This memory MUST be released with + * |NS_Free|/|osfile_ns_free|. + */ +MOZ_EXPORT_API(PRUnichar*) osfile_DecodeAll( + const char* aEncoding, + const char* aSource, + const int32_t aBytesToDecode); + +/** + * Encode a complete Unicode string into a set of bytes. + * + * @param aEncoding The encoding to use. + * @param aSource The Unicode string to encode. Must be nul-terminated. + * @param aBytesWritten (out) The number of bytes encoded. + * + * @return null in case of error, otherwise a new buffer. The + * number of bytes actually allocated may be higher than + * |aBytesWritten|. The buffer MUST be released with + * |NS_Free|/|osfile_ns_free|. + */ +MOZ_EXPORT_API(char*) osfile_EncodeAll( + const char* aEncoding, + const PRUnichar* aSource, + int32_t* aBytesWritten); + +} // extern "C" + +#endif // mozilla_osfileutils_h__