From 4f1f41f338ce0899e48605c82375a72883f4eb7c Mon Sep 17 00:00:00 2001 From: tsepez Date: Mon, 28 Mar 2016 14:13:16 -0700 Subject: Added test for util.printx() and make it match spec. R=dsinclair@chromium.org Review URL: https://codereview.chromium.org/1837543002 --- fpdfsdk/javascript/PublicMethods.cpp | 39 ++--- fpdfsdk/javascript/util.cpp | 161 ++++++++++++--------- fpdfsdk/javascript/util.h | 5 +- testing/resources/javascript/util_printx.in | 88 +++++++++++ .../resources/javascript/util_printx_expected.txt | 35 +++++ 5 files changed, 226 insertions(+), 102 deletions(-) create mode 100644 testing/resources/javascript/util_printx.in create mode 100644 testing/resources/javascript/util_printx_expected.txt diff --git a/fpdfsdk/javascript/PublicMethods.cpp b/fpdfsdk/javascript/PublicMethods.cpp index b85111bed7..a4c13564c8 100644 --- a/fpdfsdk/javascript/PublicMethods.cpp +++ b/fpdfsdk/javascript/PublicMethods.cpp @@ -1424,39 +1424,31 @@ FX_BOOL CJS_PublicMethods::AFSpecial_Format( return FALSE; } - std::string cFormat; - int iIndex = params[0].ToInt(); - CJS_EventHandler* pEvent = pContext->GetEventHandler(); if (!pEvent->m_pValue) return FALSE; - CFX_WideString& Value = pEvent->Value(); - std::string strSrc = CFX_ByteString::FromUnicode(Value).c_str(); - switch (iIndex) { + CFX_WideString wsSource = pEvent->Value(); + CFX_WideString wsFormat; + switch (params[0].ToInt()) { case 0: - cFormat = "99999"; + wsFormat = L"99999"; break; case 1: - cFormat = "99999-9999"; + wsFormat = L"99999-9999"; break; - case 2: { - std::string NumberStr; - util::printx("9999999999", strSrc, NumberStr); - if (NumberStr.length() >= 10) - cFormat = "(999) 999-9999"; + case 2: + if (util::printx(L"9999999999", wsSource).GetLength() >= 10) + wsFormat = L"(999) 999-9999"; else - cFormat = "999-9999"; + wsFormat = L"999-9999"; break; - } case 3: - cFormat = "999-99-9999"; + wsFormat = L"999-99-9999"; break; } - std::string strDes; - util::printx(cFormat, strSrc, strDes); - Value = CFX_WideString::FromLocal(strDes.c_str()); + pEvent->Value() = util::printx(wsFormat, wsSource); return TRUE; } @@ -1578,22 +1570,15 @@ FX_BOOL CJS_PublicMethods::AFSpecial_Keystroke( cFormat = "99999"; break; case 1: - // cFormat = "99999-9999"; cFormat = "999999999"; break; - case 2: { - std::string NumberStr; - util::printx("9999999999", strSrc, NumberStr); + case 2: if (strSrc.length() + wstrChange.length() > 7) - // cFormat = "(999) 999-9999"; cFormat = "9999999999"; else - // cFormat = "999-9999"; cFormat = "9999999"; break; - } case 3: - // cFormat = "999-99-9999"; cFormat = "999999999"; break; } diff --git a/fpdfsdk/javascript/util.cpp b/fpdfsdk/javascript/util.cpp index 30656cd766..f7b2d7fbfa 100644 --- a/fpdfsdk/javascript/util.cpp +++ b/fpdfsdk/javascript/util.cpp @@ -309,96 +309,113 @@ FX_BOOL util::printx(IJS_Context* cc, const std::vector& params, CJS_Value& vRet, CFX_WideString& sError) { - int iSize = params.size(); - if (iSize < 2) + if (params.size() < 2) { + sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR); return FALSE; - CFX_WideString sFormat = params[0].ToCFXWideString(); - CFX_WideString sSource = params[1].ToCFXWideString(); - std::string cFormat = CFX_ByteString::FromUnicode(sFormat).c_str(); - std::string cSource = CFX_ByteString::FromUnicode(sSource).c_str(); - std::string cDest; - printx(cFormat, cSource, cDest); - vRet = cDest.c_str(); + } + vRet = printx(params[0].ToCFXWideString(), params[1].ToCFXWideString()); return TRUE; } -void util::printx(const std::string& cFormat, - const std::string& cSource2, - std::string& cPurpose) { - std::string cSource(cSource2); - if (!cPurpose.empty()) - // cPurpose.clear(); - cPurpose.erase(); - int itSource = 0; - int iSize = cSource.size(); - for (int iIndex = 0; iIndex < (int)cFormat.size() && itSource < iSize; - iIndex++) { - char letter = cFormat[iIndex]; - switch (letter) { - case '?': - cPurpose += cSource[itSource]; - itSource++; - break; +enum CaseMode { kPreserveCase, kUpperCase, kLowerCase }; + +static FX_WCHAR TranslateCase(FX_WCHAR input, CaseMode eMode) { + if (eMode == kLowerCase && input >= 'A' && input <= 'Z') + return input | 0x20; + if (eMode == kUpperCase && input >= 'a' && input <= 'z') + return input & ~0x20; + return input; +} + +CFX_WideString util::printx(const CFX_WideString& wsFormat, + const CFX_WideString& wsSource) { + CFX_WideString wsResult; + FX_STRSIZE iSourceIdx = 0; + FX_STRSIZE iFormatIdx = 0; + CaseMode eCaseMode = kPreserveCase; + bool bEscaped = false; + while (iFormatIdx < wsFormat.GetLength()) { + if (bEscaped) { + bEscaped = false; + wsResult += wsFormat[iFormatIdx]; + ++iFormatIdx; + continue; + } + switch (wsFormat[iFormatIdx]) { + case '\\': { + bEscaped = true; + ++iFormatIdx; + } break; + case '<': { + eCaseMode = kLowerCase; + ++iFormatIdx; + } break; + case '>': { + eCaseMode = kUpperCase; + ++iFormatIdx; + } break; + case '=': { + eCaseMode = kPreserveCase; + ++iFormatIdx; + } break; + case '?': { + if (iSourceIdx < wsSource.GetLength()) { + wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); + ++iSourceIdx; + } + ++iFormatIdx; + } break; case 'X': { - while (itSource < iSize) { - if (std::isdigit(cSource[itSource]) || - (cSource[itSource] >= 'a' && cSource[itSource] <= 'z') || - (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) { - cPurpose += cSource[itSource]; - itSource++; - break; + if (iSourceIdx < wsSource.GetLength()) { + if ((wsSource[iSourceIdx] >= '0' && wsSource[iSourceIdx] <= '9') || + (wsSource[iSourceIdx] >= 'a' && wsSource[iSourceIdx] <= 'z') || + (wsSource[iSourceIdx] >= 'A' && wsSource[iSourceIdx] <= 'Z')) { + wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); + ++iFormatIdx; } - itSource++; + ++iSourceIdx; + } else { + ++iFormatIdx; } - break; } break; case 'A': { - while (itSource < iSize) { - if ((cSource[itSource] >= 'a' && cSource[itSource] <= 'z') || - (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) { - cPurpose += cSource[itSource]; - itSource++; - break; + if (iSourceIdx < wsSource.GetLength()) { + if ((wsSource[iSourceIdx] >= 'a' && wsSource[iSourceIdx] <= 'z') || + (wsSource[iSourceIdx] >= 'A' && wsSource[iSourceIdx] <= 'Z')) { + wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); + ++iFormatIdx; } - itSource++; + ++iSourceIdx; + } else { + ++iFormatIdx; } - break; } break; case '9': { - while (itSource < iSize) { - if (std::isdigit(cSource[itSource])) { - cPurpose += cSource[itSource]; - itSource++; - break; + if (iSourceIdx < wsSource.GetLength()) { + if (wsSource[iSourceIdx] >= '0' && wsSource[iSourceIdx] <= '9') { + wsResult += wsSource[iSourceIdx]; + ++iFormatIdx; } - itSource++; + ++iSourceIdx; + } else { + ++iFormatIdx; } - break; - } + } break; case '*': { - cPurpose.append(cSource, itSource, iSize - itSource); - itSource = iSize - 1; - break; - } - case '\\': - break; - case '>': { - for (char& c : cSource) - c = toupper(c); - break; - } - case '<': { - for (char& c : cSource) - c = tolower(c); - break; - } - case '=': - break; - default: - cPurpose += letter; - break; + if (iSourceIdx < wsSource.GetLength()) { + wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode); + ++iSourceIdx; + } else { + ++iFormatIdx; + } + } break; + default: { + wsResult += wsFormat[iFormatIdx]; + ++iFormatIdx; + } break; } } + return wsResult; } FX_BOOL util::scand(IJS_Context* cc, diff --git a/fpdfsdk/javascript/util.h b/fpdfsdk/javascript/util.h index 17f252d6dc..3022efece2 100644 --- a/fpdfsdk/javascript/util.h +++ b/fpdfsdk/javascript/util.h @@ -38,9 +38,8 @@ class util : public CJS_EmbedObj { CJS_Value& vRet, CFX_WideString& sError); - static void printx(const std::string& cFormat, - const std::string& cSource, - std::string& cPurpose); + static CFX_WideString printx(const CFX_WideString& cFormat, + const CFX_WideString& cSource); }; class CJS_Util : public CJS_Object { diff --git a/testing/resources/javascript/util_printx.in b/testing/resources/javascript/util_printx.in new file mode 100644 index 0000000000..7085edc3ea --- /dev/null +++ b/testing/resources/javascript/util_printx.in @@ -0,0 +1,88 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R + /OpenAction 10 0 R +>> +endobj +{{object 2 0}} << + /Type /Pages + /Count 1 + /Kids [ + 3 0 R + ] +>> +endobj +% Page number 0. +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /Resources << + /Font <> + >> + /Contents [21 0 R] + /MediaBox [0 0 612 792] +>> +% OpenAction action +{{object 10 0}} << + /Type /Action + /S /JavaScript + /JS 11 0 R +>> +endobj +% JS program to exexute +{{object 11 0}} << +>> +stream +function TestOneFormat(fmt, src) { + var title = "('" + fmt + "', '" + src + "')"; + try { + app.alert(title + " => '" + util.printx(fmt, src) + "'"); + } + catch (e) { + app.alert(title + ": Caught error: " + e); + } +} +TestOneFormat("", ""); +TestOneFormat("", "123"); +TestOneFormat("??", ""); +TestOneFormat("??", "f2"); +TestOneFormat("??", "f27"); +TestOneFormat("XXX", ""); +TestOneFormat("XXX", "1afp3."); +TestOneFormat("XXX", "-1Afp3.d33F$"); +TestOneFormat("AAA", ""); +TestOneFormat("AAA", "-1Afp3."); +TestOneFormat("AAA", "-1Afp3.d33F$"); +TestOneFormat("999", ""); +TestOneFormat("999", "-1Afp3."); +TestOneFormat("999", "-1Afp3.d33F$"); +TestOneFormat("9*9", ""); +TestOneFormat("9*9", "-1Afp3."); +TestOneFormat("[*]X", "-1Afp3."); +TestOneFormat("<*", "-1Afp3.d33F$"); +TestOneFormat(">*", "-1Afp3.d33F$"); +TestOneFormat("<[AAAAAAAAAAA]", "-1Afp3.d33F$"); +TestOneFormat(">[AAAAAAAAAAA]", "-1Afp3.d33F$"); +TestOneFormat("<[XXXXXXXXXXX]", "-1Afp3.d33F$"); +TestOneFormat(">[XXXXXXXXXXX]", "-1Afp3.d33F$"); +TestOneFormat("<[XXXXXXXXXXX]", "-1Afp3.d33F$"); +TestOneFormat(">[???????????]", "-1Afp3.d33F$"); +TestOneFormat("<[???????????]", "-1Afp3.d33F$"); +TestOneFormat("\\>[\\**]", "-1Afp3.d33F$"); +TestOneFormat("\\>[\\\\**]", "-1Afp3.d33F$"); +TestOneFormat("=*", "-1Afp3.d33F$"); +TestOneFormat("??????=*", "-1Afp3.d33F$"); +TestOneFormat(">??????<*", "-1Afp3.d33F$"); +TestOneFormat("clams", "-1Afp3.d33F$"); +TestOneFormat("cl9ms", "-1Afp3.d33F$"); +TestOneFormat("cl\\9ms", "-1Afp3.d33F$"); +endstream +endobj +{{xref}} +trailer << + /Root 1 0 R +>> +{{startxref}} +%%EOF diff --git a/testing/resources/javascript/util_printx_expected.txt b/testing/resources/javascript/util_printx_expected.txt new file mode 100644 index 0000000000..124767d5fd --- /dev/null +++ b/testing/resources/javascript/util_printx_expected.txt @@ -0,0 +1,35 @@ +Alert: ('', '') => '' +Alert: ('', '123') => '' +Alert: ('??', '') => '' +Alert: ('??', 'f2') => 'f2' +Alert: ('??', 'f27') => 'f2' +Alert: ('XXX', '') => '' +Alert: ('XXX', '1afp3.') => '1af' +Alert: ('XXX', '-1Afp3.d33F$') => '1Af' +Alert: ('AAA', '') => '' +Alert: ('AAA', '-1Afp3.') => 'Afp' +Alert: ('AAA', '-1Afp3.d33F$') => 'Afp' +Alert: ('999', '') => '' +Alert: ('999', '-1Afp3.') => '13' +Alert: ('999', '-1Afp3.d33F$') => '133' +Alert: ('9*9', '') => '' +Alert: ('9*9', '-1Afp3.') => '1Afp3.' +Alert: ('[*]X', '-1Afp3.') => '[-1Afp3.]' +Alert: ('<*', '-1Afp3.d33F$') => '-1afp3.d33f$' +Alert: ('>*', '-1Afp3.d33F$') => '-1AFP3.D33F$' +Alert: ('<[AAAAAAAAAAA]', '-1Afp3.d33F$') => '[afpdf]' +Alert: ('>[AAAAAAAAAAA]', '-1Afp3.d33F$') => '[AFPDF]' +Alert: ('<[XXXXXXXXXXX]', '-1Afp3.d33F$') => '[1afp3d33f]' +Alert: ('>[XXXXXXXXXXX]', '-1Afp3.d33F$') => '[1AFP3D33F]' +Alert: ('<[XXXXXXXXXXX]', '-1Afp3.d33F$') => '[1afp3d33f]' +Alert: ('>[???????????]', '-1Afp3.d33F$') => '[-1AFP3.D33F]' +Alert: ('<[???????????]', '-1Afp3.d33F$') => '[-1afp3.d33f]' +Alert: ('\>[\**]', '-1Afp3.d33F$') => '>[*-1Afp3.d33F$]' +Alert: ('\>[\\**]', '-1Afp3.d33F$') => '>[\-1Afp3.d33F$]' +Alert: ('=*', '-1Afp3.d33F$') => '-1Afp3.d33F$' +Alert: (' '-1afp3.d33F$' +Alert: ('>??????=*', '-1Afp3.d33F$') => '-1AFP3.d33F$' +Alert: ('>??????<*', '-1Afp3.d33F$') => '-1AFP3.d33f$' +Alert: ('clams', '-1Afp3.d33F$') => 'clams' +Alert: ('cl9ms', '-1Afp3.d33F$') => 'cl1ms' +Alert: ('cl\9ms', '-1Afp3.d33F$') => 'cl9ms' -- cgit v1.2.3