diff --git a/engine/src/wolf.system/io/w_io.c b/engine/src/wolf.system/io/w_io.c index 0b7288d7..0df26289 100644 --- a/engine/src/wolf.system/io/w_io.c +++ b/engine/src/wolf.system/io/w_io.c @@ -1,27 +1,49 @@ #include "w_io.h" + +#include #include -#include +#include +#include + +#include "base64/chromiumbase64.h" +#include "base64/fastavx512bwbase64.h" +#include "base64/fastavxbase64.h" +#include "base64/klompavxbase64.h" +#include "base64/quicktimebase64.h" +#include "base64/scalarbase64.h" #ifdef W_PLATFORM_UNIX +#include "base64/linuxbase64.h" #include #include #endif -apr_file_t* w_io_create_file(_In_z_ const char* pPath, - _In_z_ const char* pContent, - _In_ const bool pBinaryMode, - _In_ const bool pBufferedMode, - _In_ const bool pNoneBlockMode, - _In_ const bool pMultiThreadedMode, - _In_ const bool pOpenAppendMode, - _In_ const bool pIsLargFile, - _In_ const bool pErrorIfFileExists) +#include +#include +#define PNG_BYTES_TO_CHECK 4 +#define PNG_PAGING_SIZE 8 + +struct png_context { + void* data; + int len; + int pos; +}; + +w_file w_io_file_create(_In_z_ const char* pPath, + _In_z_ const char* pContent, + _In_ bool pBinaryMode, + _In_ bool pBufferedMode, + _In_ bool pNoneBlockMode, + _In_ bool pMultiThreadedMode, + _In_ bool pOpenAppendMode, + _In_ bool pIsLargFile, + _In_ bool pErrorIfFileExists) { apr_status_t _ret = APR_SUCCESS; apr_file_t* _file = NULL; apr_size_t _buffer_len = 0; apr_int32_t _flags = 0; - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { W_ASSERT(false, "could not get default memory. trace info: w_io_create_directory"); @@ -77,21 +99,21 @@ apr_file_t* w_io_create_file(_In_z_ const char* pPath, return _file; } -W_RESULT w_io_save_to_file(_In_z_ const char* pPath, - _In_z_ const char* pContent, - _In_ const bool pBinaryMode, - _In_ const bool pBufferedMode, - _In_ const bool pNoneBlockMode, - _In_ const bool pMultiThreadedMode, - _In_ const bool pOpenAppendMode, - _In_ const bool pIsLargFile, - _In_ const bool pErrorIfFileExists) +W_RESULT w_io_file_save(_In_z_ const char* pPath, + _In_z_ const char* pContent, + _In_ bool pBinaryMode, + _In_ bool pBufferedMode, + _In_ bool pNoneBlockMode, + _In_ bool pMultiThreadedMode, + _In_ bool pOpenAppendMode, + _In_ bool pIsLargFile, + _In_ bool pErrorIfFileExists) { apr_status_t _ret = APR_SUCCESS; apr_file_t* _file = NULL; apr_size_t _buffer_len = 0; apr_int32_t _flags = 0; - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { W_ASSERT(false, "could not get default memory. trace info: w_io_create_directory"); @@ -146,15 +168,15 @@ W_RESULT w_io_save_to_file(_In_z_ const char* pPath, __return: apr_file_close(_file); - return _ret == APR_SUCCESS ? W_PASSED : W_FAILED; + return _ret == APR_SUCCESS ? W_SUCCESS : W_FAILURE; } -W_RESULT w_io_get_is_file(_In_z_ const char* pPath) +W_RESULT w_io_file_check_is_file(_In_z_ const char* pPath) { #ifdef W_PLATFORM_UNIX struct stat _stat; int _ret = stat(pPath, &_stat); - return _ret == -1 ? W_FAILED : W_PASSED; + return _ret == -1 ? W_FAILURE : W_SUCCESS; #else //on Windows FILE* _file = NULL; @@ -162,18 +184,18 @@ W_RESULT w_io_get_is_file(_In_z_ const char* pPath) if (_file) { fclose(_file); - return W_PASSED; + return W_SUCCESS; } - return W_FAILED; + return W_FAILURE; #endif } -apr_finfo_t* w_io_get_file_info_from_path(_In_z_ const char* pPath) +w_file_info w_io_file_get_info_from_path(_In_z_ const char* pPath) { - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { - W_ASSERT(false, "could not get default memory. trace info: w_string_create"); + W_ASSERT(false, "could not get default memory. trace info: w_io_get_file_info_from_path"); return NULL; } @@ -195,12 +217,12 @@ apr_finfo_t* w_io_get_file_info_from_path(_In_z_ const char* pPath) * @param pFile opened file * @return file info */ -apr_finfo_t* w_io_get_file_info(_In_ apr_file_t* pFile) +w_file_info w_io_file_get_info(_In_ w_file pFile) { - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { - W_ASSERT(false, "could not get default memory. trace info: w_string_create"); + W_ASSERT(false, "could not get default memory. trace info: w_io_get_file_info"); return NULL; } @@ -217,21 +239,21 @@ apr_finfo_t* w_io_get_file_info(_In_ apr_file_t* pFile) return NULL; } -const char* w_io_get_file_extension_from_path(_In_z_ const char* pFilePath) +const char* w_io_file_get_extension_from_path(_In_z_ const char* pFilePath) { const char* _dot = strrchr(pFilePath, '.'); if(!_dot || _dot == pFilePath) return ""; return _dot + 1; } -const char* w_io_get_file_extension(_In_ apr_file_t* pFile) +const char* w_io_file_get_extension(_In_ w_file pFile) { - apr_finfo_t* _info = w_io_get_file_info(pFile); + apr_finfo_t* _info = w_io_file_get_info(pFile); if (!_info) return ""; - return w_io_get_file_extension_from_path(_info->fname); + return w_io_file_get_extension_from_path(_info->fname); } -const char* w_io_get_base_file_name_from_path(_In_z_ const char* pPath) +const char* w_io_file_get_base_name_from_path(_In_z_ const char* pPath) { // traverse from right size_t _len = strlen(pPath); @@ -247,20 +269,20 @@ const char* w_io_get_base_file_name_from_path(_In_z_ const char* pPath) if (_index == -1) return ""; - char* _dst_str = w_string_create(_index); + char* _dst_str = w_malloc(_index, "w_io_get_base_file_name_from_path"); apr_cpystrn(_dst_str, pPath,_index); _dst_str[_index] = '\0'; return _dst_str; } -const char* w_io_get_base_file_name(_In_ apr_file_t* pFile) +const char* w_io_file_get_base_name(_In_ w_file pFile) { - apr_finfo_t* _info = w_io_get_file_info(pFile); + apr_finfo_t* _info = w_io_file_get_info(pFile); return _info->fname; } -const char* w_io_get_file_name_from_path(_In_z_ const char* pFilePath) +const char* w_io_file_get_name_from_path(_In_z_ const char* pFilePath) { #ifdef W_PLATFORM_UNIX char* _s = strdup(pFilePath); @@ -270,98 +292,123 @@ const char* w_io_get_file_name_from_path(_In_z_ const char* pFilePath) #endif } -const char* w_io_get_file_name(_In_ apr_file_t* pFile) +const char* w_io_file_get_name(_In_ w_file pFile) { - apr_finfo_t* _info = w_io_get_file_info(pFile); + apr_finfo_t* _info = w_io_file_get_info(pFile); if (!_info) return ""; return _info->name; } -void* w_io_read_file_with_path(_In_z_ const char* pPath) +w_file_istream w_io_file_read_full_from_path(_In_z_ const char* pPath) { - void* _buf = NULL; - apr_pool_t* _pool = w_get_default_memory_pool(); + return w_io_file_read_nbytes_from_path(pPath, 0); +} + +w_file_istream w_io_file_read_nbytes_from_path(_In_z_ const char* pPath, _In_ size_t pNBytes) +{ + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { - W_ASSERT(false, "could not get default memory. trace info: w_io_create_directory"); + W_ASSERT(false, "could not get default memory. trace info: w_io_file_read_nbytes_from_path"); return NULL; } + w_file_istream _istream = w_malloc(sizeof(w_file_input_stream), "w_io_file_read_nbytes_from_path"); + if (!_istream) + { + return NULL; + } apr_file_t* _file = NULL; apr_status_t _ret = apr_file_open(&_file, pPath, - APR_FOPEN_READ | APR_FOPEN_BUFFERED, - 0, + APR_READ, + APR_OS_DEFAULT, _pool); if (_ret == APR_SUCCESS) { //read it all - apr_size_t _size_of_file = apr_file_buffer_size_get(_file); - apr_size_t _bytes_read = 0; - apr_file_read_full(_file, _buf, _size_of_file, &_bytes_read); - apr_file_close(_file); + apr_finfo_t _finfo; + _ret = apr_file_info_get(&_finfo, APR_FINFO_NORM, _file); + if (_ret == APR_SUCCESS) + { + _istream->size = _finfo.size; + _istream->buffer = w_malloc(_istream->size, "w_io_file_read_nbytes_from_path(file buffer)"); + _istream->bytes_read = _istream->size; + apr_file_read(_file, _istream->buffer, &_istream->bytes_read); + apr_file_close(_file); + } } - return _buf; + return _istream; } -void* w_io_read_file_with_file(_In_z_ apr_file_t* pFile) +w_file_istream w_io_file_read_full(_In_ w_file pFile) { - void* _buf = NULL; - apr_pool_t* _pool = w_get_default_memory_pool(); + return w_io_file_read_nbytes(pFile, 0); +} + +w_file_istream w_io_file_read_nbytes(_In_ w_file pFile, _In_ size_t pNBytes) +{ + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { - W_ASSERT(false, "could not get default memory. trace info: w_io_create_directory"); + W_ASSERT(false, "could not get default memory. trace info: w_io_file_read_nbytes"); + return NULL; + } + + w_file_istream _istream = w_malloc(sizeof(w_file_input_stream), "w_io_file_read_nbytes"); + if (!_istream) + { return NULL; } //read it all - apr_size_t _bytes_read = 0; - apr_size_t _size_of_file = apr_file_buffer_size_get(pFile); - apr_file_read_full(pFile, _buf, _size_of_file, &_bytes_read); + _istream->size = apr_file_buffer_size_get(pFile); + _istream->bytes_read = pNBytes; + apr_file_read(pFile, _istream->buffer, &_istream->bytes_read); apr_file_close(pFile); - return _buf; + return _istream; } -W_RESULT w_io_delete_file_with_path(_In_ const char* pPath) +W_RESULT w_io_file_delete_from_path(_In_ const char* pPath) { if (!pPath) { - W_ASSERT(false, "pPath is NULL. trace info: w_io_delete_file_with_path"); - return W_FAILED; + W_ASSERT(false, "pPath is NULL. trace info: w_io_file_delete_from_path"); + return W_FAILURE; } - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { - W_ASSERT(false, "could not get default memory. trace info: w_io_delete_file_with_path"); - return W_FAILED; + W_ASSERT(false, "could not get default memory. trace info: w_io_file_delete_from_path"); + return W_FAILURE; } apr_status_t _ret = apr_file_remove(pPath, _pool); - return _ret == APR_SUCCESS ? W_PASSED : W_FAILED; + return _ret == APR_SUCCESS ? W_SUCCESS : W_FAILURE; } -W_RESULT w_io_delete_file_with_file(_In_ apr_file_t* pFile) +W_RESULT w_io_file_delete(_In_ w_file pFile) { if (!pFile) { W_ASSERT(false, "could not get default memory. trace info: w_io_delete_file_with_file"); - return W_FAILED; + return W_FAILURE; } - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { W_ASSERT(false, "could not get default memory. trace info: w_io_delete_file_with_file"); - return W_FAILED; + return W_FAILURE; } - apr_finfo_t* _file = w_io_get_file_info(pFile); + apr_finfo_t* _file = w_io_file_get_info(pFile); apr_status_t _ret = apr_file_remove(_file->fname, _pool); - return _ret == APR_SUCCESS ? W_PASSED : W_FAILED; + return _ret == APR_SUCCESS ? W_SUCCESS : W_FAILURE; } -char* w_io_get_current_directory(void) +char* w_io_dir_get_current(void) { - char* _path = w_string_create(PATH_MAX); + char* _path = (char*)w_malloc(W_PATH_MAX, "w_io_get_current_directory"); #ifdef W_PLATFORM_UNIX if (getcwd(_path, PATH_MAX) == NULL) return NULL; #else @@ -370,22 +417,22 @@ char* w_io_get_current_directory(void) return _path; } -W_RESULT w_io_get_is_directory(_In_z_ const char* pPath) +W_RESULT w_io_dir_check_is_directory(_In_z_ const char* pPath) { - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { W_ASSERT(false, "could not get default memory. trace info: w_io_get_is_directory"); - return W_FAILED; + return W_FAILURE; } //open a directory apr_dir_t* _dir = NULL; apr_status_t _ret = apr_dir_open(&_dir, pPath, _pool); - return _ret == APR_SUCCESS ? W_PASSED : W_FAILED; + return _ret == APR_SUCCESS ? W_SUCCESS : W_FAILURE; } -const char* w_io_get_parent_directory(_In_z_ const char* pPath) +const char* w_io_dir_get_parent(_In_z_ const char* pPath) { #ifdef W_PLATFORM_UNIX char* _s = strdup(pPath); @@ -403,28 +450,28 @@ const char* w_io_get_parent_directory(_In_z_ const char* pPath) //copy strings if (_size == 0) return ""; - return w_string_init_with_string(pPath); + return w_string(pPath); #endif } -W_RESULT w_io_create_directory(_In_z_ const char* pPath) +W_RESULT w_io_dir_create(_In_z_ const char* pPath) { - apr_pool_t* _pool = w_get_default_memory_pool(); + w_mem_pool _pool = w_get_default_memory_pool(); if(!_pool) { W_ASSERT(false, "could not get default memory. trace info: w_io_create_directory"); - return W_FAILED; + return W_FAILURE; } //create a directory apr_status_t _ret = apr_dir_make_recursive(pPath, APR_OS_DEFAULT, _pool); - return _ret == APR_SUCCESS ? W_PASSED : W_FAILED; + return _ret == APR_SUCCESS ? W_SUCCESS : W_FAILURE; } W_RESULT w_io_utf8_to_ucs2( char* in, size_t* inbytes, - apr_uint16_t* out, + uint16_t* out, size_t* outwords) { apr_int64_t newch, mask; @@ -446,7 +493,7 @@ W_RESULT w_io_utf8_to_ucs2( if ((ch & 0300) != 0300) { /* Multibyte Continuation is out of place */ - return W_INVALID; + return APR_BADARG; } else { @@ -460,38 +507,38 @@ W_RESULT w_io_utf8_to_ucs2( while ((ch & mask) == mask) { mask |= mask >> 1; if (++expect > 3) /* (truly 5 for ucs-4) */ - return W_INVALID; + return APR_BADARG; } newch = ch & ~mask; eating = expect + 1; if (*inbytes <= expect) - return W_INCOMPLETE; + return APR_BADARG; /* Reject values of excessive leading 0 bits * utf-8 _demands_ the shortest possible byte length */ if (expect == 1) { if (!(newch & 0036)) - return W_INVALID; + return APR_BADARG; } else { /* Reject values of excessive leading 0 bits */ if (!newch && !((unsigned char)* in & 0077 & (mask << 1))) - return W_INVALID; + return APR_BADARG; if (expect == 2) { /* Reject values D800-DFFF when not utf16 encoded * (may not be an appropriate restriction for ucs-4) */ if (newch == 0015 && ((unsigned char)* in & 0040)) - return W_INVALID; + return APR_BADARG; } else if (expect == 3) { /* Short circuit values > 110000 */ if (newch > 4) - return W_INVALID; + return APR_BADARG; if (newch == 4 && ((unsigned char)* in & 0060)) - return W_INVALID; + return APR_BADARG; } } /* Where the boolean (expect > 2) is true, we will need @@ -503,7 +550,7 @@ W_RESULT w_io_utf8_to_ucs2( { /* Multibyte Continuation must be legal */ if (((ch = (unsigned char) * (in++)) & 0300) != 0200) - return W_INVALID; + return APR_BADARG; newch <<= 6; newch |= (ch & 0077); } @@ -530,11 +577,11 @@ W_RESULT w_io_utf8_to_ucs2( /* Buffer full 'errors' aren't errors, the client must inspect both * the inbytes and outwords values */ - return W_PASSED; + return W_SUCCESS; } W_RESULT w_io_ucs2_to_utf8( - apr_uint16_t* in, + uint16_t* in, size_t* inwords, char* out, size_t* outbytes) @@ -558,7 +605,7 @@ W_RESULT w_io_ucs2_to_utf8( if ((ch & 0xFC00) == 0xDC00) { /* Invalid Leading ucs-2 Multiword Continuation Character */ - return W_INVALID; + return APR_BADARG; } if ((ch & 0xFC00) == 0xD800) { /* Leading ucs-2 Multiword Character @@ -566,12 +613,12 @@ W_RESULT w_io_ucs2_to_utf8( if (*inwords < 2) { /* Missing ucs-2 Multiword Continuation Character */ - return W_INCOMPLETE; + return APR_BADARG; } if (((unsigned short)(*in) & 0xFC00) != 0xDC00) { /* Invalid ucs-2 Multiword Continuation Character */ - return W_INVALID; + return APR_BADARG; } newch = (ch & 0x03FF) << 10 | ((unsigned short)(*in++) & 0x03FF); newch += 0x10000; @@ -586,7 +633,7 @@ W_RESULT w_io_ucs2_to_utf8( require = newch >> 11; need = 1; while (require) - require >>= 5, ++need; + (void)(require >>= 5), ++need; if (need >= *outbytes) break; /* Insufficient buffer */ *inwords -= (need > 2) + 1; @@ -610,7 +657,545 @@ W_RESULT w_io_ucs2_to_utf8( /* Buffer full 'errors' aren't errors, the client must inspect both * the inwords and outbytes values */ - return W_PASSED; + return W_SUCCESS; +} + +long w_io_to_hex(_In_z_ const char* pHexStr) +{ + return strtol(pHexStr, NULL, 16); +} + +W_RESULT w_io_string_has_start_with(_In_z_ const char* pString, _In_z_ const char* pStartWith) +{ + return strncmp(pStartWith, pString, strlen(pStartWith)); +} + +W_RESULT w_io_string_has_end_with(_In_z_ const char* pString, _In_z_ const char* pEndWith) +{ + size_t _str_size = strlen(pString); + size_t _str_end_size = strlen(pEndWith); + + if (_str_size >= _str_end_size) + { + return strncmp(pString + _str_size - _str_end_size, pEndWith, _str_end_size) == 0; + } + return W_FAILURE; +} + +W_RESULT w_io_wstring_has_start_with(_In_z_ const wchar_t* pString, _In_z_ const wchar_t* pStartWith) +{ + return wcsncmp(pStartWith, pString, wcslen(pStartWith)); +} + +W_RESULT w_io_wstring_has_end_with(_In_z_ const wchar_t* pString, _In_z_ const wchar_t* pEndWith) +{ + size_t _str_size = wcslen(pString); + size_t _str_end_size = wcslen(pEndWith); + + if (_str_size >= _str_end_size) + { + return wcsncmp(pString + _str_size - _str_end_size, pEndWith, _str_end_size) == 0; + } + return W_FAILURE; +} + +W_RESULT w_io_string_split(_In_z_ char* pString, + _In_z_ const char* pSplit, + _Out_ w_array* pResults) +{ + w_mem_pool _mem_pool = w_get_default_memory_pool(); + if (!_mem_pool) + { + W_ASSERT(false, "could not get default memory pool. trace info: w_io_split_string_then_convert_to_chars"); + return W_FAILURE; + } + //create array with default size + if (*pResults) + { + w_free(*pResults); + } + *pResults = apr_array_make(_mem_pool, 32, sizeof(const char*)); + if (!*pResults) + { + W_ASSERT(false, "could not create array. trace info: w_io_split_string_then_convert_to_chars"); + return W_FAILURE; + } + + char* _splits = strtok(pString, pSplit); + // loop through the string and extract all other splits + while( _splits != NULL ) + { + *(const char**)apr_array_push(*pResults) = _splits; + _splits = strtok(NULL, pSplit); + } + + return W_SUCCESS; +} + +size_t w_io_to_base_64(_Inout_z_ char** pDestinationBuffer, + _In_z_ char* pSourceBuffer, + _In_z_ size_t pSourceBufferLenght, + _In_ base_64_mode pEncodeMode) +{ + size_t _encoded_size = 0; + switch (pEncodeMode) + { + case chromium: + _encoded_size = chromium_base64_encode( + *pDestinationBuffer, + pSourceBuffer, + pSourceBufferLenght); + break; + case klomp_avx: + klomp_avx2_base64_encode( + pSourceBuffer, + pSourceBufferLenght, + *pDestinationBuffer, + &_encoded_size); + break; + case fast_avx: + _encoded_size = fast_avx2_base64_encode( + *pDestinationBuffer, + pSourceBuffer, + pSourceBufferLenght); + break; + case fast_avx512: +#if USE_AVX512 != 0 && ((defined(_MSC_VER) && _MSC_VER >= 1911) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1600) || (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && __GNUC__ >= 5)) + _encoded_size = fast_avx512bw_base64_encode( + pDestinationBuffer, + pSourceBuffer, + pSourceBufferLenght); +#endif + break; + case quick_time: + _encoded_size = (size_t)(quicktime_base64_encode( + *pDestinationBuffer, + pSourceBuffer, + (int)pSourceBufferLenght)); + break; + case scalar: + scalar_base64_encode( + pSourceBuffer, + pSourceBufferLenght, + *pDestinationBuffer, + &_encoded_size); + break; + } + return _encoded_size; +} + +W_RESULT w_io_file_is_jpeg(_In_ const char* pFilePath) +{ + w_file_istream _istream = w_io_file_read_full_from_path(pFilePath); + return w_io_stream_is_jpeg(_istream); +} + +W_RESULT w_io_stream_is_jpeg(_In_ w_file_istream pFileStream) +{ + tjhandle _tj_handle = tjInitDecompress(); + + if (!_tj_handle) + { + return W_FAILURE; + } + + int _width, _height, _sub_sample, _color_space; + W_RESULT _rt = tjDecompressHeader3(_tj_handle, + pFileStream->buffer, + pFileStream->bytes_read, + &_width, + &_height, + &_sub_sample, + &_color_space); + tjDestroy(_tj_handle); + + return _rt; +} + +W_RESULT w_io_pixels_from_jpeg_stream(_In_z_ const uint8_t* pJpegStream, + _In_ size_t pJpegStreamLen, + _In_ w_jpeg_pixel_format pPixelFormat, + _Out_ int* pWidth, + _Out_ int* pHeight, + _Out_ int* pSubSample, + _Out_ int* pColorSpace, + _Out_ int* pNumberOfPasses, + _Out_ uint8_t** pPixels) +{ + W_RESULT _rt; + tjhandle _tj_handle = NULL; + + if (pPixelFormat == TJPF_UNKNOWN) + { + _rt = APR_BADARG; + goto out; + } + + _tj_handle = tjInitDecompress(); + if (!_tj_handle) + { + _rt = W_FAILURE; + goto out; + } + + if ((_rt = tjDecompressHeader3(_tj_handle, + pJpegStream, + pJpegStreamLen, + pWidth, + pHeight, + pSubSample, + pColorSpace))) + { + _rt = tjGetErrorCode(_tj_handle); + W_ASSERT_P(false, "tjDecompressHeader3 failed. error code %d . error message %s .trace info: w_io_pixels_from_jpeg_stream", _rt, tjGetErrorStr2(_tj_handle)); + goto out; + } + + int _comp; + switch (pPixelFormat) + { + default: + _comp = 4; + case TJPF_RGB: + case TJPF_BGR: + _comp = 3; + break; + } + + size_t _memory_size = (size_t)_comp * (size_t)(*pWidth) * (size_t)(*pHeight) * sizeof(uint8_t); + *pPixels = (uint8_t*)w_malloc(_memory_size, "w_io_pixels_from_jpeg_stream"); + _rt = tjDecompress2( + _tj_handle, + pJpegStream, + pJpegStreamLen, + *pPixels, + *pWidth, + _comp * (*pWidth), + *pHeight, + pPixelFormat, + 0); +out: + if (_tj_handle) + { + tjDestroy(_tj_handle); + } + return _rt; +} + +W_RESULT w_io_pixels_from_jpeg_file(_In_z_ const char* pJpegFile, + _In_ w_jpeg_pixel_format pPixelFormat, + _Out_ int* pWidth, + _Out_ int* pHeight, + _Out_ int* pSubSample, + _Out_ int* pColorSpace, + _Out_ int* pNumberOfPasses, + _Out_ uint8_t** pPixels) +{ + w_file_istream _istream = w_io_file_read_full_from_path(pJpegFile); + return w_io_pixels_from_jpeg_stream((const uint8_t*)_istream->buffer, + _istream->bytes_read, + pPixelFormat, + pWidth, + pHeight, + pSubSample, + pColorSpace, + pNumberOfPasses, + pPixels); +} + +W_RESULT w_io_stream_is_png(_In_ w_file_istream pFileStream) +{ + uint8_t _buf[PNG_BYTES_TO_CHECK]; + memcpy(_buf, pFileStream->buffer, PNG_BYTES_TO_CHECK); + //Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + return png_sig_cmp(_buf, 0, PNG_BYTES_TO_CHECK); +} + +W_RESULT w_io_file_is_png(_In_z_ const char* pFilePath) +{ + w_file_istream _fs = w_io_file_read_nbytes_from_path(pFilePath, PNG_BYTES_TO_CHECK); + W_RESULT _result = png_sig_cmp(_fs->buffer, 0, PNG_BYTES_TO_CHECK); + if (_fs) + { + if (_fs->buffer) + w_free(_fs->buffer); + w_free(_fs); + } + + return _result; +} + +static void _png_user_read_data( + png_structp pPngPtr, + png_bytep pData, + png_size_t pLength) +{ + struct png_context* context; + + context = png_get_io_ptr(pPngPtr); + if (pLength > context->pos + context->len) + pLength = context->len - context->pos; + memcpy(pData, (char*)context->data + context->pos, pLength); + context->pos += pLength; + + //cast istream + //png_voidp _io = png_get_io_ptr(pPngPtr); + //memcpy(pData, _io, pLength); +} + +W_RESULT w_io_pixels_from_png_stream(_In_ w_file_istream pFileStream, + _In_ w_png_pixel_format pPixelFormat, + _Out_ int* pWidth, + _Out_ int* pHeight, + _Out_ uint8_t* pColorType, + _Out_ uint8_t* pBitDepth, + _Out_ int* pNumberOfPasses, + _Out_ uint8_t** pPixels) +{ + if(png_sig_cmp(pFileStream->buffer, 0, PNG_BYTES_TO_CHECK)) + { + W_ASSERT(false, "file stream does not contain png data. trace info: w_io_pixels_from_png_stream::png_sig_cmp"); + return APR_BADARG; + } + + //initialize stuff + png_structp _png_ptr = png_create_read_struct( + PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if (!_png_ptr) + { + W_ASSERT(false, "could not create png pointer. trace info: w_io_pixels_from_png_stream::png_create_read_struct"); + return W_FAILURE; + } + + png_infop _info_ptr = png_create_info_struct(_png_ptr); + if (!_info_ptr) + { + W_ASSERT(false, "could not create info struct. trace info: w_io_pixels_from_png_stream::png_create_info_struct"); + return W_FAILURE; + } + + if (setjmp(png_jmpbuf(_png_ptr))) + { + png_destroy_read_struct(&_png_ptr, &_info_ptr, (png_infopp)0); + + W_ASSERT(false, "failed on setjmp. trace info: w_io_pixels_from_png_stream::setjmp"); + return W_FAILURE; + } + + struct png_context context; + + context.data = pFileStream->buffer; + context.len = pFileStream->bytes_read; + context.pos = PNG_PAGING_SIZE; + + png_set_read_fn(_png_ptr, &context, &_png_user_read_data);//png_init_io(_png_ptr, _file); + //png_init_io(_png_ptr, ) + png_set_sig_bytes(_png_ptr, PNG_PAGING_SIZE); + png_read_info(_png_ptr, _info_ptr); + + *pWidth = (int)png_get_image_width(_png_ptr, _info_ptr); + *pHeight = (int)png_get_image_height(_png_ptr, _info_ptr); + *pColorType = png_get_color_type(_png_ptr, _info_ptr); + *pBitDepth = png_get_bit_depth(_png_ptr, _info_ptr); + *pNumberOfPasses = png_set_interlace_handling(_png_ptr); + + //check bit depth + if (*pBitDepth == 16) + { + png_set_strip_16(_png_ptr); + } + + if (*pColorType == PNG_COLOR_TYPE_PALETTE) + { + png_set_palette_to_rgb(_png_ptr); + } + + // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16 bit depth. + if (*pColorType == PNG_COLOR_TYPE_GRAY && *pBitDepth < 8) + { + png_set_expand_gray_1_2_4_to_8(_png_ptr); + } + + if (png_get_valid(_png_ptr, _info_ptr, PNG_INFO_tRNS)) + { + png_set_tRNS_to_alpha(_png_ptr); + } + + // These color_type don't have an alpha channel then fill it with 0xff. + if (*pColorType == PNG_COLOR_TYPE_RGB || + *pColorType == PNG_COLOR_TYPE_GRAY || + *pColorType == PNG_COLOR_TYPE_PALETTE) + { + png_set_filler(_png_ptr, 0xFF, PNG_FILLER_AFTER); + } + + if (*pColorType == PNG_COLOR_TYPE_GRAY || *pColorType == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_gray_to_rgb(_png_ptr); + } + + png_read_update_info(_png_ptr, _info_ptr); + + //now data must be rgba + size_t _comp = 4; + if (pPixelFormat == RGB_PNG || + pPixelFormat == BGR_PNG) + { + _comp = 3; + } + + //allocate memory + if (pPixels && *pPixels) + { + w_free(*pPixels); + } + (*pPixels) = (uint8_t*)w_malloc(_comp * (size_t)(*pWidth) * (size_t)(*pHeight) * sizeof(uint8_t), + "w_io_pixels_from_png_stream"); + + size_t _bytes_per_row = png_get_rowbytes(_png_ptr, _info_ptr); + uint8_t* _raw_data = (uint8_t*)w_malloc(_bytes_per_row, "w_io_pixels_from_png_stream"); + + //pixels counter + uint32_t _k = 0; + + //read single row at a time and then convert it to desired pixel format + switch (pPixelFormat) + { + case RGB_PNG: + for (int i = 0; i < (*pHeight); ++i) + { + png_read_row(_png_ptr, (png_bytep)_raw_data, NULL); + + //const int _row_offset = i * (*pWidth); + + size_t _byte_index = 0; + for (int j = 0; j < (*pWidth); ++j) + { + const uint8_t _r = _raw_data[_byte_index++]; + const uint8_t _g = _raw_data[_byte_index++]; + const uint8_t _b = _raw_data[_byte_index++]; + _byte_index++;//alpha ignored + + (*pPixels)[_k] = _r; + (*pPixels)[_k + 1] = _g; + (*pPixels)[_k + 2] = _b; + + _k += _comp; + } + } + break; + case BGR_PNG: + for (int i = 0; i < *pHeight; ++i) + { + png_read_row(_png_ptr, (png_bytep)_raw_data, NULL); + + //const auto _row_offset = i * pWidth; + + size_t _byte_index = 0; + for (int j = 0; j < *pWidth; ++j) + { + const uint8_t _r = _raw_data[_byte_index++]; + const uint8_t _g = _raw_data[_byte_index++]; + const uint8_t _b = _raw_data[_byte_index++]; + _byte_index++;//alpha ignored + + (*pPixels)[_k] = _b; + (*pPixels)[_k + 1] = _g; + (*pPixels)[_k + 2] = _r; + + _k += _comp; + } + } + break; + case RGBA_PNG: + for (int i = 0; i < *pHeight; ++i) + { + png_read_row(_png_ptr, (png_bytep)_raw_data, NULL); + + //const auto _row_offset = i * (*pWidth); + + uint32_t _byte_index = 0; + for (int j = 0; j < (*pWidth); ++j) + { + const uint8_t _r = _raw_data[_byte_index++]; + const uint8_t _g = _raw_data[_byte_index++]; + const uint8_t _b = _raw_data[_byte_index++]; + const uint8_t _a = _raw_data[_byte_index++]; + + (*pPixels)[_k] = _r; + (*pPixels)[_k + 1] = _g; + (*pPixels)[_k + 2] = _b; + (*pPixels)[_k + 3] = _a; + + _k += _comp; + } + } + break; + case BGRA_PNG: + for (int i = 0; i < *pHeight; ++i) + { + png_read_row(_png_ptr, (png_bytep)_raw_data, NULL); + + //const auto _row_offset = i * pWidth; + + uint32_t _byte_index = 0; + for (int j = 0; j < *pWidth; ++j) + { + const uint32_t _r = _raw_data[_byte_index++]; + const uint32_t _g = _raw_data[_byte_index++]; + const uint32_t _b = _raw_data[_byte_index++]; + const uint32_t _a = _raw_data[_byte_index++]; + + (*pPixels)[_k] = _b; + (*pPixels)[_k + 1] = _g; + (*pPixels)[_k + 2] = _r; + (*pPixels)[_k + 3] = _a; + + _k += _comp; + } + } + break; + }; + + png_destroy_read_struct(&_png_ptr, &_info_ptr, (png_infopp)0); + w_free(_raw_data); + + return W_SUCCESS; +} + +W_RESULT w_io_pixels_from_png_file(_In_ const char* pFilePath, + _In_ w_png_pixel_format pPixelFormat, + _Out_ int* pWidth, + _Out_ int* pHeight, + _Out_ uint8_t* pColorType, + _Out_ uint8_t* pBitDepth, + _Out_ int* pNumberOfPasses, + _Out_ uint8_t** pPixels) +{ + w_file_istream _fs = w_io_file_read_full_from_path(pFilePath); + W_RESULT _result = w_io_pixels_from_png_stream(_fs, + pPixelFormat, + pWidth, + pHeight, + pColorType, + pBitDepth, + pNumberOfPasses, + pPixels); + + if (_fs) + { + if (_fs->buffer) + { + w_free(_fs->buffer); + } + + w_free(_fs); + } + + return _result; } //apr_dir_read(<#apr_finfo_t *finfo#>, <#apr_int32_t wanted#>, <#apr_dir_t *thedir#>) @@ -886,143 +1471,3 @@ W_RESULT w_io_ucs2_to_utf8( // // } - -// -//#pragma region PNG Methods -// -// //is stream contains png data -// inline W_RESULT is_png_file(_Inout_ std::istream& pStream) -// { -// return w_image::is_png_file(pStream); -// } -// -// //is file contains png data -// inline W_RESULT is_png_file(_In_z_ const char* pFilePath) -// { -// return w_image::is_png_file(pFilePath); -// } -// -// /* -// read png from stream -// pState indicates the state -// 0 means the succeded -// 1 means file is not png -// -1 means the file could not be opened for reading -// -2 means internal function error -// */ -// inline uint8_t* read_png_from_stream(_Inout_ std::istream& pStream, -// _Out_ int& pWidth, -// _Out_ int& pHeight, -// _Out_ uint8_t& pColorType, -// _Out_ uint8_t& pBitDepth, -// _Out_ int& pNumberOfPasses, -// _Out_ int& pState, -// _In_ const w_png_pixel_format& pPixelFormat = w_png_pixel_format::RGBA_PNG) -// { -// return w_image::read_png_from_stream( -// pStream, -// pWidth, -// pHeight, -// pColorType, -// pBitDepth, -// pNumberOfPasses, -// pState, -// pPixelFormat); -// } -// -// /* -// read png from file -// pState indicates the state -// 0 means the succeded -// 1 means file is not png -// -1 means the file could not be opened for reading -// -2 means internal function error -// */ -// inline uint8_t* read_png_from_file( -// _In_z_ const char* pFilePath, -// _Out_ int& pWidth, -// _Out_ int& pHeight, -// _Out_ uint8_t& pColorType, -// _Out_ uint8_t& pBitDepth, -// _Out_ int& pNumberOfPasses, -// _Out_ int& pState, -// _In_ const w_png_pixel_format& pPixelFormat = w_png_pixel_format::RGBA_PNG) -// { -// return w_image::read_png_from_file( -// pFilePath, -// pWidth, -// pHeight, -// pColorType, -// pBitDepth, -// pNumberOfPasses, -// pState, -// pPixelFormat); -// } -// -//#pragma endregion -// -//#pragma region JPEG Methods -// -// /* -// read jpg from stream -// pState indicates the state -// 0 means the succeded -// 1 means file is not jpg -// -1 means the file could not be opened for reading -// -2 means internal function error -// */ -// inline uint8_t* read_jpeg_from_stream( -// _In_z_ std::istream& pStream, -// _Out_ int& pWidth, -// _Out_ int& pHeight, -// _Out_ int& pSubSample, -// _Out_ int& pColorSpace, -// _Out_ int& pNumberOfPasses, -// _Out_ int& pState, -// _In_ const w_jpeg_pixel_format& pPixelFormat = w_jpeg_pixel_format::RGB_JPEG) -// { -// return w_image::read_jpeg_from_stream( -// pStream, -// pWidth, -// pHeight, -// pSubSample, -// pColorSpace, -// pNumberOfPasses, -// pState, -// pPixelFormat); -// } -// -// /* -// read jpg from file -// pState indicates the state -// 0 means the succeded -// 1 means file is not jpg -// -1 means the file could not be opened for reading -// -2 means internal function error -// */ -// inline uint8_t* read_jpeg_from_file( -// _In_z_ const char* pFilePath, -// _Out_ int& pWidth, -// _Out_ int& pHeight, -// _Out_ int& pSubSample, -// _Out_ int& pColorSpace, -// _Out_ int& pNumberOfPasses, -// _Out_ int& pState, -// _In_ const w_jpeg_pixel_format& pPixelFormat = w_jpeg_pixel_format::RGB_JPEG) -// { -// return w_image::read_jpeg_from_file( -// pFilePath, -// pWidth, -// pHeight, -// pSubSample, -// pColorSpace, -// pNumberOfPasses, -// pState, -// pPixelFormat); -// } -// -//#pragma endregion -// -//} -// -//#endif //__W_IO_H__