mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-28 16:41:52 +08:00
1299 lines
44 KiB
C++
1299 lines
44 KiB
C++
//
|
|
// Notice Regarding Standards. AMD does not provide a license or sublicense to
|
|
// any Intellectual Property Rights relating to any standards, including but not
|
|
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
|
|
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3
|
|
// (collectively, the "Media Technologies"). For clarity, you will pay any
|
|
// royalties due for such third party technologies, which may include the Media
|
|
// Technologies that are owed as a result of AMD providing the Software to you.
|
|
//
|
|
// MIT license
|
|
//
|
|
//
|
|
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
//
|
|
|
|
#include "AMFSTL.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <locale>
|
|
#include <locale.h>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <wchar.h>
|
|
#include <stdarg.h>
|
|
#if defined(__ANDROID__)
|
|
#include <codecvt>
|
|
#endif
|
|
|
|
#if !defined(__APPLE__) && !defined(_WIN32)
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
#pragma warning(disable: 4996)
|
|
|
|
#if defined(__linux) || defined(__APPLE__)
|
|
extern "C"
|
|
{
|
|
extern int vscwprintf(const wchar_t* p_fmt, va_list p_args);
|
|
extern int vscprintf(const char* p_fmt, va_list p_args);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#define snprintf _snprintf
|
|
#define vscprintf _vscprintf
|
|
#define vscwprintf _vscwprintf // Count chars without writing to string
|
|
#define vswprintf _vsnwprintf
|
|
#endif
|
|
|
|
|
|
using namespace amf;
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
|
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
|
#endif
|
|
|
|
static const amf_string AMF_FORBIDDEN_SYMBOLS = ":? %,;@&=+$<>#\"";
|
|
static const amf_string AMF_FORBIDDEN_SYMBOLS_QUERY = ":? %,;@+$<>#\"";
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
|
|
//MM: in question: unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
// string conversaion
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_from_unicode_to_utf8(const amf_wstring& str)
|
|
{
|
|
amf_string result;
|
|
if(0 == str.size())
|
|
{
|
|
return result;
|
|
}
|
|
#if defined(_WIN32)
|
|
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
|
#endif
|
|
|
|
|
|
const wchar_t* pwBuff = str.c_str();
|
|
|
|
#if defined(_WIN32)
|
|
int Utf8BuffSize = ::WideCharToMultiByte(CP_UTF8, 0, pwBuff, -1, NULL, 0, NULL, NULL);
|
|
if(0 == Utf8BuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
Utf8BuffSize += 8; // get some extra space
|
|
result.resize(Utf8BuffSize);
|
|
Utf8BuffSize = ::WideCharToMultiByte(CP_UTF8, 0, pwBuff, -1, &result[0], Utf8BuffSize, NULL, NULL);
|
|
Utf8BuffSize--;
|
|
#elif defined(__ANDROID__)
|
|
char* old_locale = setlocale(LC_CTYPE, "en_US.UTF8");
|
|
int Utf8BuffSize = str.length();
|
|
if(0 == Utf8BuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
Utf8BuffSize += 8; // get some extra space
|
|
result.resize(Utf8BuffSize);
|
|
|
|
mbstate_t mbs;
|
|
mbrlen(NULL, 0, &mbs);
|
|
|
|
Utf8BuffSize = 0;
|
|
for( int i = 0; i < str.length(); i++)
|
|
{
|
|
//MM TODO Android - not implemented
|
|
//int written = wcrtomb(&result[Utf8BuffSize], pwBuff[i], &mbs);
|
|
result[Utf8BuffSize] = (char)(pwBuff[i]);
|
|
int written = 1;
|
|
// temp replacement
|
|
Utf8BuffSize += written;
|
|
}
|
|
setlocale(LC_CTYPE, old_locale);
|
|
|
|
#else
|
|
char* old_locale = setlocale(LC_CTYPE, "en_US.UTF8");
|
|
int Utf8BuffSize = wcstombs(NULL, pwBuff, 0);
|
|
if(0 == Utf8BuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
Utf8BuffSize += 8; // get some extra space
|
|
result.resize(Utf8BuffSize);
|
|
Utf8BuffSize = wcstombs(&result[0], pwBuff, Utf8BuffSize);
|
|
|
|
setlocale(LC_CTYPE, old_locale);
|
|
#endif
|
|
result.resize(Utf8BuffSize);
|
|
|
|
|
|
return result;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_from_utf8_to_unicode(const amf_string& str)
|
|
{
|
|
amf_wstring result;
|
|
if(0 == str.size())
|
|
{
|
|
return result;
|
|
}
|
|
#if defined(_WIN32)
|
|
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
|
#endif
|
|
|
|
|
|
const char* pUtf8Buff = str.c_str();
|
|
|
|
#if defined(_WIN32)
|
|
int UnicodeBuffSize = ::MultiByteToWideChar(CP_UTF8, 0, pUtf8Buff, -1, NULL, 0);
|
|
if(0 == UnicodeBuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
UnicodeBuffSize += 8; // get some extra space
|
|
result.resize(UnicodeBuffSize);
|
|
UnicodeBuffSize = ::MultiByteToWideChar(CP_UTF8, 0, pUtf8Buff, -1, &result[0], UnicodeBuffSize);
|
|
UnicodeBuffSize--;
|
|
|
|
#elif defined(__ANDROID__)
|
|
//MM on android mbstowcs cannot be used to define length
|
|
char* old_locale = setlocale(LC_CTYPE, "en_US.UTF8");
|
|
|
|
mbstate_t mbs;
|
|
mbrlen(NULL, 0, &mbs);
|
|
int len = str.length();
|
|
const char* pt = pUtf8Buff;
|
|
int UnicodeBuffSize = 0;
|
|
while(len > 0)
|
|
{
|
|
size_t length = mbrlen (pt, len, &mbs); //MM TODO Android always return 1
|
|
if((length == 0) || (length > len))
|
|
{
|
|
break;
|
|
}
|
|
UnicodeBuffSize++;
|
|
len -= length;
|
|
pt += length;
|
|
}
|
|
UnicodeBuffSize += 8; // get some extra space
|
|
result.resize(UnicodeBuffSize);
|
|
|
|
mbrlen (NULL, 0, &mbs);
|
|
len = str.length();
|
|
pt = pUtf8Buff;
|
|
UnicodeBuffSize = 0;
|
|
while(len > 0)
|
|
{
|
|
size_t length = mbrlen (pt, len, &mbs);
|
|
if((length == 0) || (length > len))
|
|
{
|
|
break;
|
|
}
|
|
mbrtowc(&result[UnicodeBuffSize], pt, length, &mbs); //MM TODO Android always return 1 char
|
|
UnicodeBuffSize++;
|
|
len -= length;
|
|
pt += length;
|
|
}
|
|
setlocale(LC_CTYPE, old_locale);
|
|
|
|
#else
|
|
char* old_locale = setlocale(LC_CTYPE, "en_US.UTF8");
|
|
int UnicodeBuffSize = mbstowcs(NULL, pUtf8Buff, 0);
|
|
if(0 == UnicodeBuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
UnicodeBuffSize += 8; // get some extra space
|
|
result.resize(UnicodeBuffSize);
|
|
UnicodeBuffSize = mbstowcs(&result[0], pUtf8Buff, UnicodeBuffSize);
|
|
setlocale(LC_CTYPE, old_locale);
|
|
#endif
|
|
result.resize(UnicodeBuffSize);
|
|
|
|
|
|
return result;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_from_unicode_to_multibyte(const amf_wstring& str)
|
|
{
|
|
amf_string result;
|
|
if(0 == str.size())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
const wchar_t* pwBuff = str.c_str();
|
|
|
|
#if defined(__ANDROID__)
|
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
|
result.assign(converter.to_bytes(pwBuff).c_str());
|
|
/*
|
|
int Utf8BuffSize = str.length();
|
|
if(0 == Utf8BuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
Utf8BuffSize += 8; // get some extra space
|
|
result.resize(Utf8BuffSize);
|
|
|
|
mbstate_t mbs;
|
|
mbrlen(NULL, 0, &mbs);
|
|
|
|
Utf8BuffSize = 0;
|
|
for( int i = 0; i < str.length(); i++)
|
|
{
|
|
//MM TODO Android - not implemented
|
|
//int written = wcrtomb(&result[Utf8BuffSize], pwBuff[i], &mbs);
|
|
result[Utf8BuffSize] = (char)(pwBuff[i]);
|
|
int written = 1;
|
|
// temp replacement
|
|
Utf8BuffSize += written;
|
|
}
|
|
result.resize(Utf8BuffSize);
|
|
*/
|
|
#else
|
|
amf_size Utf8BuffSize = wcstombs(NULL, pwBuff, 0);
|
|
if(static_cast<std::size_t>(-1) == Utf8BuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
Utf8BuffSize += 8; // get some extra space
|
|
result.resize(Utf8BuffSize);
|
|
Utf8BuffSize = wcstombs(&result[0], pwBuff, Utf8BuffSize);
|
|
result.resize(Utf8BuffSize);
|
|
#endif
|
|
return result;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_from_multibyte_to_unicode(const amf_string& str)
|
|
{
|
|
amf_wstring result;
|
|
if(0 == str.size())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
const char* pUtf8Buff = str.c_str();
|
|
|
|
|
|
#if defined(__ANDROID__)
|
|
//MM on android mbstowcs cannot be used to define length
|
|
mbstate_t mbs;
|
|
mbrlen(NULL, 0, &mbs);
|
|
int len = str.length();
|
|
const char* pt = pUtf8Buff;
|
|
int UnicodeBuffSize = 0;
|
|
while(len > 0)
|
|
{
|
|
size_t length = mbrlen (pt, len, &mbs); //MM TODO Android always return 1
|
|
if((length == 0) || (length > len))
|
|
{
|
|
break;
|
|
}
|
|
UnicodeBuffSize++;
|
|
len -= length;
|
|
pt += length;
|
|
}
|
|
UnicodeBuffSize += 8; // get some extra space
|
|
result.resize(UnicodeBuffSize);
|
|
|
|
mbrlen (NULL, 0, &mbs);
|
|
len = str.length();
|
|
pt = pUtf8Buff;
|
|
UnicodeBuffSize = 0;
|
|
while(len > 0)
|
|
{
|
|
size_t length = mbrlen (pt, len, &mbs);
|
|
if((length == 0) || (length > len))
|
|
{
|
|
break;
|
|
}
|
|
mbrtowc(&result[UnicodeBuffSize], pt, length, &mbs); //MM TODO Android always return 1 char
|
|
UnicodeBuffSize++;
|
|
len -= length;
|
|
pt += length;
|
|
}
|
|
#else
|
|
amf_size UnicodeBuffSize = mbstowcs(NULL, pUtf8Buff, 0);
|
|
if(0 == UnicodeBuffSize)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
UnicodeBuffSize += 8; // get some extra space
|
|
result.resize(UnicodeBuffSize);
|
|
UnicodeBuffSize = mbstowcs(&result[0], pUtf8Buff, UnicodeBuffSize);
|
|
#endif
|
|
result.resize(UnicodeBuffSize);
|
|
return result;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_from_string_to_hex_string(const amf_string& str)
|
|
{
|
|
amf_string ret;
|
|
char buf[10];
|
|
for(int i = 0; i < (int)str.length(); i++)
|
|
{
|
|
sprintf(buf, "%02X", (unsigned char)str[i]);
|
|
ret += buf;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_from_hex_string_to_string(const amf_string& str)
|
|
{
|
|
amf_string ret;
|
|
char buf[3] = {
|
|
0, 0, 0
|
|
};
|
|
for(int i = 0; i < (int)str.length(); i += 2)
|
|
{
|
|
buf[0] = str[i];
|
|
buf[1] = str[i + 1];
|
|
int tmp = 0;
|
|
sscanf(buf, "%2X", &tmp);
|
|
ret += (char)tmp;
|
|
}
|
|
return ret;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_string_to_lower(const amf_string& str)
|
|
{
|
|
std::locale loc;
|
|
amf_string out = str.c_str();
|
|
size_t iLen = out.length();
|
|
for(size_t i = 0; i < iLen; i++)
|
|
{
|
|
out[i] = std::tolower (out[i], loc);
|
|
}
|
|
return out;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_string_to_lower(const amf_wstring& str)
|
|
{
|
|
std::locale loc;
|
|
amf_wstring out = str.c_str();
|
|
size_t iLen = out.length();
|
|
for(size_t i = 0; i < iLen; i++)
|
|
{
|
|
out[i] = std::tolower (out[i], loc);
|
|
}
|
|
return out;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_string_to_upper(const amf_string& str)
|
|
{
|
|
std::locale loc;
|
|
amf_string out = str.c_str();
|
|
size_t iLen = out.length();
|
|
for(size_t i = 0; i < iLen; i++)
|
|
{
|
|
out[i] = std::toupper (out[i], loc);
|
|
}
|
|
return out;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_string_to_upper(const amf_wstring& str)
|
|
{
|
|
std::locale loc;
|
|
amf_wstring out = str.c_str();
|
|
size_t iLen = out.length();
|
|
for(size_t i = 0; i < iLen; i++)
|
|
{
|
|
out[i] = std::toupper (out[i], loc);
|
|
}
|
|
return out;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_convert_path_to_os_accepted_path(const amf_wstring& path)
|
|
{
|
|
amf_wstring result = path;
|
|
amf_wstring::size_type pos = 0;
|
|
while(pos != amf_string::npos)
|
|
{
|
|
pos = result.find(L'/', pos);
|
|
if(pos == amf_wstring::npos)
|
|
{
|
|
break;
|
|
}
|
|
result[pos] = PATH_SEPARATOR_WCHAR;
|
|
pos++;
|
|
}
|
|
return result;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_convert_path_to_url_accepted_path(const amf_wstring& path)
|
|
{
|
|
amf_wstring result = path;
|
|
amf_wstring::size_type pos = 0;
|
|
while(pos != amf_string::npos)
|
|
{
|
|
pos = result.find(L'\\', pos);
|
|
if(pos == amf_wstring::npos)
|
|
{
|
|
break;
|
|
}
|
|
result[pos] = L'/';
|
|
pos++;
|
|
}
|
|
return result;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
//------------------------------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_from_unicode_to_url_utf8(const amf_wstring& data, bool bQuery) // converts to UTF8 and replace fobidden symbols
|
|
{
|
|
amf_string converted = amf_from_unicode_to_utf8(amf_convert_path_to_url_accepted_path(data));
|
|
// convert all necessary symbols to hex
|
|
amf_string Result;
|
|
|
|
amf_size num = converted.length();
|
|
char buf[20];
|
|
for(amf_size i = 0; i < num; i++)
|
|
{
|
|
if((converted[i] <= 0x20) || (converted[i] >= 0x7F) ||
|
|
(bQuery && ( AMF_FORBIDDEN_SYMBOLS.find(converted[i]) != amf_string::npos) ) ||
|
|
(!bQuery && ( AMF_FORBIDDEN_SYMBOLS_QUERY.find(converted[i]) != amf_string::npos) ))
|
|
{
|
|
snprintf(buf, sizeof(buf), "%%%02X", (unsigned int)(unsigned char)converted[i]);
|
|
}
|
|
else
|
|
{
|
|
buf[0] = converted[i];
|
|
buf[1] = 0;
|
|
}
|
|
Result += buf;
|
|
}
|
|
return Result;
|
|
}
|
|
//------------------------------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_from_url_utf8_to_unicode(const amf_string& data)
|
|
{
|
|
amf_string Result;
|
|
amf_string::size_type pos = 0;
|
|
while(pos != amf_string::npos)
|
|
{
|
|
amf_string::size_type old_pos = pos;
|
|
pos = data.find('%', pos);
|
|
if(pos == amf_string::npos)
|
|
{
|
|
Result += data.substr(old_pos);
|
|
break;
|
|
}
|
|
if(pos - old_pos > 0)
|
|
{
|
|
Result += data.substr(old_pos, pos - old_pos);
|
|
}
|
|
char buf[5] = {
|
|
'0', 'x', 0, 0, 0
|
|
};
|
|
buf[2] = data[pos + 1];
|
|
buf[3] = data[pos + 2];
|
|
char* ret = NULL;
|
|
|
|
Result += (char)strtol(buf, &ret, 16);
|
|
pos += 3;
|
|
}
|
|
|
|
amf_wstring converted = amf_from_utf8_to_unicode(Result);
|
|
|
|
return converted;
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
amf_size AMF_STD_CALL amf::amf_string_ci_find(const amf_wstring& left, const amf_wstring& right, amf_size off)
|
|
{
|
|
amf_wstring _left = amf_string_to_lower(left);
|
|
amf_wstring _right = amf_string_to_lower(right);
|
|
return _left.find(_right, off);
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
amf_size AMF_STD_CALL amf::amf_string_ci_rfind(const amf_wstring& left, const amf_wstring& right, amf_size off)
|
|
{
|
|
amf_wstring _left = amf_string_to_lower(left);
|
|
amf_wstring _right = amf_string_to_lower(right);
|
|
return _left.rfind(_right, off);
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
amf_int AMF_STD_CALL amf::amf_string_ci_compare(const amf_wstring& left, const amf_wstring& right)
|
|
{
|
|
amf_wstring _left = amf_string_to_lower(left);
|
|
amf_wstring _right = amf_string_to_lower(right);
|
|
return _left.compare(_right);
|
|
}
|
|
//----------------------------------------------------------------------------------------------
|
|
amf_int AMF_STD_CALL amf::amf_string_ci_compare(const amf_string& left, const amf_string& right)
|
|
{
|
|
amf_string _left = amf_string_to_lower(left);
|
|
amf_string _right = amf_string_to_lower(right);
|
|
return _left.compare(_right);
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_string_format(const wchar_t* format, ...)
|
|
{
|
|
va_list arglist;
|
|
va_start(arglist, format);
|
|
amf_wstring text = amf_string_formatVA(format, arglist);
|
|
va_end(arglist);
|
|
|
|
return text;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_string_format(const char* format, ...)
|
|
{
|
|
va_list arglist;
|
|
va_start(arglist, format);
|
|
amf_string text = amf_string_formatVA(format, arglist);
|
|
va_end(arglist);
|
|
|
|
return text;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_wstring AMF_STD_CALL amf::amf_string_formatVA(const wchar_t* format, va_list args)
|
|
{
|
|
#if (defined(__linux) || defined(__APPLE__)) && (!defined(__ANDROID__))
|
|
//replace %s with %ls
|
|
amf_wstring text(format);
|
|
amf_wstring textReplaced;
|
|
textReplaced.reserve(text.length() * 2);
|
|
bool percentFlag = false;
|
|
for(amf_wstring::iterator i = text.begin(); i != text.end(); ++i)
|
|
{
|
|
if(percentFlag && (*i == L's'))
|
|
{
|
|
textReplaced.push_back(L'l');
|
|
textReplaced.push_back(L's');
|
|
}
|
|
else if(percentFlag && (*i == L'S'))
|
|
{
|
|
textReplaced.push_back(L's');
|
|
}
|
|
else
|
|
{
|
|
textReplaced.push_back(*i);
|
|
}
|
|
percentFlag = (*i != L'%') ? false : !percentFlag;
|
|
}
|
|
|
|
format = textReplaced.c_str();
|
|
#endif //#if defined(__linux)
|
|
va_list argcopy;
|
|
#ifdef _WIN32
|
|
argcopy = args;
|
|
#else
|
|
va_copy(argcopy, args);
|
|
#endif
|
|
int size = vscwprintf(format, argcopy);
|
|
|
|
va_end(argcopy);
|
|
|
|
|
|
std::vector<wchar_t> buf(size + 1);
|
|
wchar_t* pBuf = &buf[0];
|
|
vswprintf(pBuf, size + 1, format, args);
|
|
return pBuf;
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
amf_string AMF_STD_CALL amf::amf_string_formatVA(const char* format, va_list args)
|
|
{
|
|
va_list argcopy;
|
|
|
|
#ifdef _WIN32
|
|
argcopy = args;
|
|
#else
|
|
va_copy(argcopy, args);
|
|
#endif
|
|
int size = vscprintf(format, args);
|
|
|
|
va_end(argcopy);
|
|
|
|
std::vector<char> buf(size + 1);
|
|
char* pBuf = &buf[0];
|
|
vsnprintf(pBuf, size + 1, format, args);
|
|
return pBuf;
|
|
}
|
|
#if (defined(__linux) || defined(__APPLE__)) && !defined(__ANDROID__)
|
|
int vscprintf(const char* format, va_list argptr)
|
|
{
|
|
char* p_tmp_buf;
|
|
size_t tmp_buf_size;
|
|
FILE* fd = open_memstream(&p_tmp_buf, &tmp_buf_size);
|
|
if(fd == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
va_list arg_copy;
|
|
va_copy(arg_copy, argptr);
|
|
vfprintf(fd, format, arg_copy);
|
|
va_end(arg_copy);
|
|
fclose(fd);
|
|
free(p_tmp_buf);
|
|
return tmp_buf_size;
|
|
}
|
|
|
|
int vscwprintf(const wchar_t* format, va_list argptr)
|
|
{
|
|
wchar_t* p_tmp_buf;
|
|
size_t tmp_buf_size;
|
|
FILE* fd = open_wmemstream(&p_tmp_buf, &tmp_buf_size);
|
|
if(fd == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
va_list arg_copy;
|
|
va_copy(arg_copy, argptr);
|
|
vfwprintf(fd, format, argptr);
|
|
va_end(arg_copy);
|
|
fclose(fd);
|
|
free(p_tmp_buf);
|
|
return tmp_buf_size;
|
|
}
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
void* AMF_STD_CALL amf_alloc(size_t count)
|
|
{
|
|
return malloc(count);
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
void AMF_STD_CALL amf_free(void* ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
void* AMF_STD_CALL amf_aligned_alloc(size_t count, size_t alignment)
|
|
{
|
|
#if defined(_WIN32)
|
|
return _aligned_malloc(count, alignment);
|
|
#elif defined (__APPLE__)
|
|
void* p = nullptr;
|
|
posix_memalign(&p, alignment, count);
|
|
return p;
|
|
#elif defined(__linux)
|
|
return memalign(alignment, count);
|
|
#endif
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
void AMF_STD_CALL amf_aligned_free(void* ptr)
|
|
{
|
|
#if defined(_WIN32)
|
|
return _aligned_free(ptr);
|
|
#else
|
|
return free(ptr);
|
|
#endif
|
|
}
|
|
//----------------------------------------------------------------------------------------
|
|
#if defined (__ANDROID__)
|
|
template <typename CHAR_T>
|
|
static bool isOneOf(CHAR_T p_ch, const CHAR_T* p_set)
|
|
{
|
|
for (const CHAR_T* current = p_set; *current != 0; ++current)
|
|
{
|
|
if (*current == p_ch)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void processWidthAndPrecision(amf_string& p_fmt, va_list& p_args)
|
|
{
|
|
for (size_t i = 0; i < p_fmt.length(); i++)
|
|
{
|
|
if (p_fmt[i] == '*')
|
|
{
|
|
int value = va_arg(p_args, int);
|
|
char valueString[64];
|
|
sprintf(valueString, "%d", value);
|
|
p_fmt.replace(i, 1, valueString);
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef size_t(*outputStreamDelegateW)(void* p_context, size_t p_offset, const wchar_t* p_stringToAdd, size_t p_length);
|
|
static size_t amf_wprintfCore(outputStreamDelegateW p_outDelegate, void* p_context, const wchar_t* p_fmt, va_list p_args)
|
|
{
|
|
static const wchar_t formatSpecifiers[] = L"cCdiouxXeEfgGaAnpsSZ";
|
|
bool inFormat = false;
|
|
const wchar_t* beginCurrentFormat = NULL;
|
|
amf_wstring::size_type formatLength = 0;
|
|
amf_wstring currentFormat;
|
|
amf_wstring currentArgumentString;
|
|
size_t totalCount = 0;
|
|
|
|
for (const wchar_t* fmt = p_fmt; *fmt != L'\0'; ++fmt)
|
|
{
|
|
if (*fmt == L'%')
|
|
{
|
|
inFormat = !inFormat;
|
|
if (inFormat) // Beginning of a format substring - fmt points at the opening %
|
|
{
|
|
beginCurrentFormat = fmt; // Save the pointer to the current format substring
|
|
formatLength = 0;
|
|
}
|
|
else // This was a percent character %% - don't bother
|
|
{
|
|
beginCurrentFormat = NULL;
|
|
}
|
|
currentFormat.clear();
|
|
}
|
|
if (inFormat)
|
|
{
|
|
++formatLength;
|
|
|
|
if (isOneOf<wchar_t>(*fmt, formatSpecifiers))
|
|
{ // end of the format specifier
|
|
inFormat = false;
|
|
currentFormat.assign(beginCurrentFormat, formatLength); // currentFormat now contains a modified format string for the current parameter
|
|
amf_string currentFormatMB = amf_from_unicode_to_multibyte(currentFormat.c_str());
|
|
//processWidthAndPrecision(currentFormatMB, &p_args[0]); // This would extract additional arguments for width and precision and replace * with their values
|
|
for (size_t i = 0; i < currentFormatMB.length(); i++)
|
|
{
|
|
if (currentFormatMB[i] == '*')
|
|
{
|
|
int value = va_arg(p_args, int);
|
|
char valueString[64];
|
|
sprintf(valueString, "%d", value);
|
|
currentFormatMB.replace(i, 1, valueString);
|
|
}
|
|
}
|
|
|
|
switch (*fmt)
|
|
{
|
|
case L'c':
|
|
{
|
|
wchar_t ch;
|
|
switch (*(fmt - 1))
|
|
{
|
|
case L'h':
|
|
ch = static_cast<wchar_t>(va_arg(p_args, int));
|
|
break;
|
|
case L'l':
|
|
case L'w':
|
|
ch = va_arg(p_args, unsigned int);
|
|
break;
|
|
default:
|
|
ch = va_arg(p_args, unsigned int); // In a wchar_t version of printf %c means wchar_t
|
|
}
|
|
currentArgumentString = ch;
|
|
}
|
|
break;
|
|
case L'C':
|
|
{
|
|
wchar_t ch;
|
|
switch (*(fmt - 1))
|
|
{
|
|
case L'h':
|
|
ch = static_cast<wchar_t>(va_arg(p_args, int));
|
|
break;
|
|
case L'l':
|
|
case L'w':
|
|
ch = va_arg(p_args, unsigned int);
|
|
break;
|
|
default:
|
|
ch = static_cast<wchar_t>(va_arg(p_args, int)); // In a wchar_t version of printf %C means char
|
|
}
|
|
currentArgumentString = ch;
|
|
}
|
|
break;
|
|
case L's':
|
|
{
|
|
const void* str = va_arg(p_args, const void*);
|
|
if (str != NULL)
|
|
{
|
|
const wchar_t* str_wchar = nullptr;
|
|
switch (*(fmt - 1))
|
|
{
|
|
case L'h':
|
|
currentArgumentString = amf_from_utf8_to_unicode(reinterpret_cast<const char*>(str));
|
|
str_wchar = currentArgumentString.c_str();
|
|
break;
|
|
case L'l':
|
|
case L'w':
|
|
currentArgumentString = str_wchar = reinterpret_cast<const wchar_t*>(str);
|
|
break;
|
|
default:
|
|
currentArgumentString = str_wchar = reinterpret_cast<const wchar_t*>(str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentArgumentString = L"(null)";
|
|
}
|
|
}
|
|
break;
|
|
case L'S':
|
|
{
|
|
const void* str = va_arg(p_args, const void*);
|
|
if (str != NULL)
|
|
{
|
|
switch (*(fmt - 1))
|
|
{
|
|
case (wchar_t)'h':
|
|
currentArgumentString = amf_from_utf8_to_unicode(reinterpret_cast<const char*>(str));
|
|
break;
|
|
case L'l':
|
|
case L'w':
|
|
currentArgumentString = reinterpret_cast<const wchar_t*>(str);
|
|
break;
|
|
default:
|
|
currentArgumentString = amf_from_utf8_to_unicode(reinterpret_cast<const char*>(str));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentArgumentString = L"(null)";
|
|
}
|
|
}
|
|
break;
|
|
// All integer formats
|
|
case L'i':
|
|
case L'd':
|
|
case L'u':
|
|
case L'o':
|
|
case L'x':
|
|
case L'X':
|
|
{
|
|
char tempBuffer[64]; // 64 bytes should be enough for any numeric format
|
|
switch (*(fmt - 1))
|
|
{
|
|
case L'l':
|
|
if (*(fmt - 2) == L'l') // long long
|
|
{
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, long long));
|
|
}
|
|
else
|
|
{
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, long));
|
|
}
|
|
break;
|
|
case L'h':
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, int));
|
|
break;
|
|
#ifdef _WIN32
|
|
case L'I': // I is Microsoft-specific
|
|
#else
|
|
case L'z': // z and t are C99-specific, but seem to be unsupported in VC
|
|
case L't':
|
|
#endif
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, size_t));
|
|
break;
|
|
default:
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, int));
|
|
break;
|
|
}
|
|
currentArgumentString = amf_from_utf8_to_unicode(tempBuffer);
|
|
}
|
|
break;
|
|
// All floating point formats
|
|
case L'e':
|
|
case L'E':
|
|
case L'f':
|
|
case L'g':
|
|
case L'G':
|
|
case L'a':
|
|
case L'A':
|
|
{
|
|
char tempBuffer[64]; // 64 bytes should be enough for any numeric format
|
|
switch (*(fmt - 1))
|
|
{
|
|
case L'l':
|
|
case L'L':
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, long double));
|
|
break;
|
|
default:
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, double));
|
|
break;
|
|
}
|
|
currentArgumentString = amf_from_utf8_to_unicode(tempBuffer);
|
|
}
|
|
break;
|
|
// Pointer
|
|
case L'p':
|
|
{
|
|
char tempBuffer[64]; // 64 bytes should be enough for any numeric format
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, const void*));
|
|
currentArgumentString = amf_from_utf8_to_unicode(tempBuffer);
|
|
}
|
|
break;
|
|
case L'n':
|
|
{
|
|
int* dest = va_arg(p_args, int*);
|
|
*dest = static_cast<int>(totalCount);
|
|
currentArgumentString.clear();
|
|
}
|
|
break;
|
|
}
|
|
size_t length = currentArgumentString.length();
|
|
if (p_outDelegate != NULL) // If destination buffer is NULL, just count the characters
|
|
{
|
|
p_outDelegate(p_context, totalCount, currentArgumentString.c_str(), length);
|
|
}
|
|
totalCount += length;
|
|
} // if (isOneOf(*fmt, formatSpecifiers))
|
|
} // if (inFormat)
|
|
else
|
|
{ // Just copy the character into the output buffer
|
|
if (p_outDelegate != NULL) // If destination buffer is NULL, just count the characters
|
|
{
|
|
p_outDelegate(p_context, totalCount, fmt, 1);
|
|
}
|
|
++totalCount;
|
|
}
|
|
}
|
|
return totalCount;
|
|
}
|
|
|
|
typedef size_t(*outputStreamDelegate)(void* p_context, size_t p_offset, const char* p_stringToAdd, size_t p_length);
|
|
static size_t amf_printfCore(outputStreamDelegate p_outDelegate, void* p_context, const char* p_fmt, va_list p_args)
|
|
{
|
|
static const char formatSpecifiers[] = "cCdiouxXeEfgGaAnpsSZ";
|
|
bool inFormat = false;
|
|
const char* beginCurrentFormat = NULL;
|
|
amf_string::size_type formatLength = 0;
|
|
amf_string currentFormat;
|
|
amf_string currentArgumentString;
|
|
size_t totalCount = 0;
|
|
|
|
for (const char* fmt = p_fmt; *fmt != '\0'; ++fmt)
|
|
{
|
|
if (*fmt == '%')
|
|
{
|
|
inFormat = !inFormat;
|
|
if (inFormat) // Beginning of a format substring - fmt points at the opening %
|
|
{
|
|
beginCurrentFormat = fmt; // Save the pointer to the current format substring
|
|
formatLength = 0;
|
|
}
|
|
else // This was a percent character %% - don't bother
|
|
{
|
|
beginCurrentFormat = NULL;
|
|
}
|
|
currentFormat.clear();
|
|
}
|
|
if (inFormat)
|
|
{
|
|
++formatLength;
|
|
|
|
if (isOneOf<char>(*fmt, formatSpecifiers))
|
|
{ // end of the format specifier
|
|
inFormat = false;
|
|
currentFormat.assign(beginCurrentFormat, formatLength); // currentFormat now contains a modified format string for the current parameter
|
|
amf_string currentFormatMB = currentFormat.c_str();
|
|
//processWidthAndPrecision(currentFormatMB, &p_args[0]); // This would extract additional arguments for width and precision and replace * with their values
|
|
for (size_t i = 0; i < currentFormatMB.length(); i++)
|
|
{
|
|
if (currentFormatMB[i] == '*')
|
|
{
|
|
int value = va_arg(p_args, int);
|
|
char valueString[64];
|
|
sprintf(valueString, "%d", value);
|
|
currentFormatMB.replace(i, 1, valueString);
|
|
}
|
|
}
|
|
|
|
switch (*fmt)
|
|
{
|
|
case 'c':
|
|
{
|
|
char ch;
|
|
switch (*(fmt - 1))
|
|
{
|
|
case 'h':
|
|
ch = static_cast<char>(va_arg(p_args, int));
|
|
break;
|
|
case 'l':
|
|
case 'w':
|
|
ch = va_arg(p_args, unsigned int);
|
|
break;
|
|
default:
|
|
ch = va_arg(p_args, unsigned int); // In a wchar_t version of printf %c means wchar_t
|
|
}
|
|
currentArgumentString = ch;
|
|
}
|
|
break;
|
|
case 'C':
|
|
{
|
|
char ch;
|
|
switch (*(fmt - 1))
|
|
{
|
|
case 'h':
|
|
ch = static_cast<char>(va_arg(p_args, int));
|
|
break;
|
|
case 'l':
|
|
case 'w':
|
|
ch = va_arg(p_args, unsigned int);
|
|
break;
|
|
default:
|
|
ch = static_cast<char>(va_arg(p_args, int)); // In a wchar_t version of printf %C means char
|
|
}
|
|
currentArgumentString = ch;
|
|
}
|
|
break;
|
|
case 's':
|
|
{
|
|
const void* str = va_arg(p_args, const void*);
|
|
if (str != NULL)
|
|
{
|
|
switch (*(fmt - 1))
|
|
{
|
|
case 'h':
|
|
currentArgumentString = reinterpret_cast<const char*>(str);
|
|
break;
|
|
case 'l':
|
|
case 'w':
|
|
currentArgumentString = amf_from_unicode_to_utf8(reinterpret_cast<const wchar_t*>(str));
|
|
break;
|
|
default:
|
|
currentArgumentString = reinterpret_cast<const char*>(str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentArgumentString = "(null)";
|
|
}
|
|
}
|
|
break;
|
|
case L'S':
|
|
{
|
|
const void* str = va_arg(p_args, const void*);
|
|
if (str != NULL)
|
|
{
|
|
switch (*(fmt - 1))
|
|
{
|
|
case 'h':
|
|
currentArgumentString = reinterpret_cast<const char*>(str);
|
|
break;
|
|
case 'l':
|
|
case 'w':
|
|
currentArgumentString = amf_from_unicode_to_utf8(reinterpret_cast<const wchar_t*>(str));
|
|
break;
|
|
default:
|
|
currentArgumentString = amf_from_unicode_to_utf8(reinterpret_cast<const wchar_t*>(str));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentArgumentString = "(null)";
|
|
}
|
|
}
|
|
break;
|
|
// All integer formats
|
|
case L'i':
|
|
case L'd':
|
|
case L'u':
|
|
case L'o':
|
|
case L'x':
|
|
case L'X':
|
|
{
|
|
char tempBuffer[64]; // 64 bytes should be enough for any numeric format
|
|
switch (*(fmt - 1))
|
|
{
|
|
case L'l':
|
|
if (*(fmt - 1) == L'l') // long long
|
|
{
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, long long));
|
|
}
|
|
else
|
|
{
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, long));
|
|
}
|
|
break;
|
|
case L'h':
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, int));
|
|
break;
|
|
#ifdef _WIN32
|
|
case L'I': // I is Microsoft-specific
|
|
#else
|
|
case L'z': // z and t are C99-specific, but seem to be unsupported in VC
|
|
case L't':
|
|
#endif
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, size_t));
|
|
break;
|
|
default:
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, int));
|
|
break;
|
|
}
|
|
currentArgumentString = tempBuffer;
|
|
}
|
|
break;
|
|
// All floating point formats
|
|
case L'e':
|
|
case L'E':
|
|
case L'f':
|
|
case L'g':
|
|
case L'G':
|
|
case L'a':
|
|
case L'A':
|
|
{
|
|
char tempBuffer[64]; // 64 bytes should be enough for any numeric format
|
|
switch (*(fmt - 1))
|
|
{
|
|
case L'l':
|
|
case L'L':
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, long double));
|
|
break;
|
|
default:
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, double));
|
|
break;
|
|
}
|
|
currentArgumentString = tempBuffer;
|
|
}
|
|
break;
|
|
// Pointer
|
|
case L'p':
|
|
{
|
|
char tempBuffer[64]; // 64 bytes should be enough for any numeric format
|
|
sprintf(tempBuffer, currentFormatMB.c_str(), va_arg(p_args, const void*));
|
|
currentArgumentString = tempBuffer;
|
|
}
|
|
break;
|
|
case L'n':
|
|
{
|
|
int* dest = va_arg(p_args, int*);
|
|
*dest = static_cast<int>(totalCount);
|
|
currentArgumentString.clear();
|
|
}
|
|
break;
|
|
}
|
|
size_t length = currentArgumentString.length();
|
|
if (p_outDelegate != NULL) // If destination buffer is NULL, just count the characters
|
|
{
|
|
p_outDelegate(p_context, totalCount, currentArgumentString.c_str(), length);
|
|
}
|
|
totalCount += length;
|
|
} // if (isOneOf(*fmt, formatSpecifiers))
|
|
} // if (inFormat)
|
|
else
|
|
{ // Just copy the character into the output buffer
|
|
if (p_outDelegate != NULL) // If destination buffer is NULL, just count the characters
|
|
{
|
|
p_outDelegate(p_context, totalCount, fmt, 1);
|
|
}
|
|
++totalCount;
|
|
}
|
|
}
|
|
return totalCount;
|
|
}
|
|
|
|
|
|
typedef struct {
|
|
wchar_t* m_Buf;
|
|
size_t m_Size;
|
|
} MemBufferContextW;
|
|
|
|
typedef struct {
|
|
char* m_Buf;
|
|
size_t m_Size;
|
|
} MemBufferContext;
|
|
|
|
static size_t writeToMem(void* p_context, size_t p_offset, const wchar_t* p_stringToAdd, size_t p_length)
|
|
{
|
|
wchar_t* buf = &(reinterpret_cast<MemBufferContextW*>(p_context)->m_Buf[p_offset]);
|
|
size_t bufSize = reinterpret_cast<MemBufferContextW*>(p_context)->m_Size - 1; // -1 to accommodate a trailing '\0'
|
|
for (int i = 0; i < p_length && i < bufSize; i++)
|
|
{
|
|
*buf++ = p_stringToAdd[i];
|
|
}
|
|
return p_length;
|
|
}
|
|
|
|
static size_t writeToFile(void* p_context, size_t, const wchar_t* p_stringToAdd, size_t p_length)
|
|
{
|
|
return fwrite(p_stringToAdd, sizeof(wchar_t), p_length, reinterpret_cast<FILE*>(p_context));
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
int vswprintf(wchar_t* p_buf, size_t p_size, const wchar_t* p_fmt, va_list p_args)
|
|
{
|
|
MemBufferContextW context = { p_buf, p_size };
|
|
int bytesWritten = (int)amf_wprintfCore(writeToMem, &context, p_fmt, p_args);
|
|
p_buf[bytesWritten] = L'\0';
|
|
return bytesWritten;
|
|
}
|
|
|
|
int wsprintf(wchar_t* p_buf, const wchar_t* p_fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
va_start(argptr, p_fmt);
|
|
return vswprintf(p_buf, static_cast<size_t>(-1), p_fmt, argptr);
|
|
}
|
|
|
|
int swprintf(wchar_t* p_buf, size_t p_size, const wchar_t* p_fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
va_start(argptr, p_fmt);
|
|
return vswprintf(p_buf, p_size, p_fmt, argptr);
|
|
}
|
|
|
|
int vfwprintf(FILE* p_stream, const wchar_t* p_fmt, va_list p_args)
|
|
{
|
|
return (int)amf_wprintfCore(writeToFile, p_stream, p_fmt, p_args);
|
|
}
|
|
|
|
int fwprintf(FILE* p_stream, const wchar_t* p_fmt, ...)
|
|
{
|
|
va_list argptr;
|
|
va_start(argptr, p_fmt);
|
|
return vfwprintf(p_stream, p_fmt, argptr);
|
|
}
|
|
|
|
#if !defined(__APPLE__)
|
|
int vscwprintf(const wchar_t* p_fmt, va_list p_args)
|
|
{
|
|
return (int)amf_wprintfCore(NULL, NULL, p_fmt, p_args);
|
|
}
|
|
|
|
int vscprintf(const char* p_fmt, va_list p_args)
|
|
{
|
|
return (int)amf_printfCore(NULL, NULL, p_fmt, p_args);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// Mac doens't have _wcsicmp(0 - poor man implementation
|
|
//--------------------------------------------------------------------------------
|
|
#ifdef __APPLE__
|
|
extern "C"
|
|
{
|
|
int _wcsicmp(const wchar_t* s1, const wchar_t* s2)
|
|
{
|
|
amf_wstring low_s1 = s1;
|
|
amf_wstring low_s2 = s2;
|
|
std::transform(low_s1.begin(), low_s1.end(), low_s1.begin(), ::tolower);
|
|
std::transform(low_s2.begin(), low_s2.end(), low_s2.begin(), ::tolower);
|
|
|
|
return wcscmp(low_s1.c_str(), low_s2.c_str());
|
|
}
|
|
}
|
|
#endif
|