Cleanup usages of Mid(foo, 1), Right(1), and Left(1)

Mid(foo, 1) is equivalent to [foo], if all you want is the character. Similarly
Left(1) is [0]. It is faster also, since it does not need to create intermediate
strings.

Right(1) is a touch more tricky, since it requires something like GetLength() ?
[GetLength() - 1] : 0;. A new method, Last() has been added to perform this
character extraction.

Multiple call sites have been updated to use more efficient/simpler
syntax. There are a number of call sites that use on these patterns, but based
on the surrounding context we actually need/want a string, so they have not been
modified.

Change-Id: I485a7f9c7b34c9bdacecada610158f996816afdd
Reviewed-on: https://pdfium-review.googlesource.com/12890
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/font/cpdf_cmap.cpp b/core/fpdfapi/font/cpdf_cmap.cpp
index 659139f..0d3745e 100644
--- a/core/fpdfapi/font/cpdf_cmap.cpp
+++ b/core/fpdfapi/font/cpdf_cmap.cpp
@@ -253,12 +253,12 @@
   m_PredefinedCMap = bsName;
   if (m_PredefinedCMap == "Identity-H" || m_PredefinedCMap == "Identity-V") {
     m_Coding = CIDCODING_CID;
-    m_bVertical = bsName[9] == 'V';
+    m_bVertical = bsName.Last() == 'V';
     m_bLoaded = true;
     return;
   }
   CFX_ByteString cmapid = m_PredefinedCMap;
-  m_bVertical = cmapid.Right(1) == "V";
+  m_bVertical = cmapid.Last() == 'V';
   if (cmapid.GetLength() > 2) {
     cmapid = cmapid.Left(cmapid.GetLength() - 2);
   }
diff --git a/core/fxcrt/cfx_bytestring.h b/core/fxcrt/cfx_bytestring.h
index a47b5f8..261060b 100644
--- a/core/fxcrt/cfx_bytestring.h
+++ b/core/fxcrt/cfx_bytestring.h
@@ -120,6 +120,9 @@
     return m_pData ? m_pData->m_String[index] : 0;
   }
 
+  CharType First() const { return GetLength() ? (*this)[0] : 0; }
+  CharType Last() const { return GetLength() ? (*this)[GetLength() - 1] : 0; }
+
   void SetAt(FX_STRSIZE index, char c);
 
   FX_STRSIZE Insert(FX_STRSIZE index, char ch);
diff --git a/core/fxcrt/cfx_string_c_template.h b/core/fxcrt/cfx_string_c_template.h
index c46b0c4..6bc71d8 100644
--- a/core/fxcrt/cfx_string_c_template.h
+++ b/core/fxcrt/cfx_string_c_template.h
@@ -135,6 +135,12 @@
     return m_Ptr.Get()[index];
   }
 
+  UnsignedType First() const { return GetLength() ? (*this)[0] : 0; }
+
+  UnsignedType Last() const {
+    return GetLength() ? (*this)[GetLength() - 1] : 0;
+  }
+
   const CharType CharAt(const FX_STRSIZE index) const {
     ASSERT(IsValidIndex(index));
     return static_cast<CharType>(m_Ptr.Get()[index]);
diff --git a/core/fxcrt/cfx_widestring.h b/core/fxcrt/cfx_widestring.h
index 2421388..100fec6 100644
--- a/core/fxcrt/cfx_widestring.h
+++ b/core/fxcrt/cfx_widestring.h
@@ -115,6 +115,9 @@
     return m_pData ? m_pData->m_String[index] : 0;
   }
 
+  CharType First() const { return GetLength() ? (*this)[0] : 0; }
+  CharType Last() const { return GetLength() ? (*this)[GetLength() - 1] : 0; }
+
   void SetAt(FX_STRSIZE index, wchar_t c);
 
   int Compare(const wchar_t* str) const;
diff --git a/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp b/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp
index 8b8b413..d2f40dd 100644
--- a/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp
+++ b/fxbarcode/datamatrix/BC_HighLevelEncoder.cpp
@@ -76,12 +76,12 @@
     return CFX_WideString();
 
   context.setAllowRectangular(allowRectangular);
-  if ((msg.Left(6) == MACRO_05_HEADER) && (msg.Right(1) == MACRO_TRAILER)) {
+  if ((msg.Left(6) == MACRO_05_HEADER) && (msg.Last() == MACRO_TRAILER)) {
     context.writeCodeword(MACRO_05);
     context.setSkipAtEnd(2);
     context.m_pos += 6;
   } else if ((msg.Left(6) == MACRO_06_HEADER) &&
-             (msg.Right(1) == MACRO_TRAILER)) {
+             (msg.Last() == MACRO_TRAILER)) {
     context.writeCodeword(MACRO_06);
     context.setSkipAtEnd(2);
     context.m_pos += 6;
diff --git a/fxbarcode/oned/BC_OnedEAN13Writer.cpp b/fxbarcode/oned/BC_OnedEAN13Writer.cpp
index 6d8d51d..dddb9cc 100644
--- a/fxbarcode/oned/BC_OnedEAN13Writer.cpp
+++ b/fxbarcode/oned/BC_OnedEAN13Writer.cpp
@@ -109,7 +109,7 @@
     return nullptr;
 
   m_iDataLenth = 13;
-  int32_t firstDigit = FXSYS_atoi(contents.Left(1).c_str());
+  int32_t firstDigit = FXSYS_DecimalCharToInt(contents.First());
   int32_t parities = FIRST_DIGIT_ENCODINGS[firstDigit];
   outLength = m_codeWidth;
   std::unique_ptr<uint8_t, FxFreeDeleter> result(
@@ -122,7 +122,7 @@
 
   int32_t i = 0;
   for (i = 1; i <= 6; i++) {
-    int32_t digit = FXSYS_atoi(contents.Mid(i, 1).c_str());
+    int32_t digit = FXSYS_DecimalCharToInt(contents[i]);
     if ((parities >> (6 - i) & 1) == 1) {
       digit += 10;
     }
@@ -135,7 +135,7 @@
     return nullptr;
 
   for (i = 7; i <= 12; i++) {
-    int32_t digit = FXSYS_atoi(contents.Mid(i, 1).c_str());
+    int32_t digit = FXSYS_DecimalCharToInt(contents[i]);
     pos += AppendPattern(result.get(), pos, L_PATTERNS[digit], 4, 1, e);
     if (e != BCExceptionNO)
       return nullptr;
diff --git a/fxbarcode/oned/BC_OnedEAN8Writer.cpp b/fxbarcode/oned/BC_OnedEAN8Writer.cpp
index 6810e9e..3fcb1e8 100644
--- a/fxbarcode/oned/BC_OnedEAN8Writer.cpp
+++ b/fxbarcode/oned/BC_OnedEAN8Writer.cpp
@@ -27,6 +27,7 @@
 #include <memory>
 #include <vector>
 
+#include "core/fxcrt/fx_extension.h"
 #include "core/fxge/cfx_defaultrenderdevice.h"
 #include "fxbarcode/BC_Writer.h"
 #include "fxbarcode/common/BC_CommonBitMatrix.h"
@@ -87,9 +88,9 @@
   int32_t even = 0;
   for (FX_STRSIZE i = contents.GetLength(); i > 0; i--) {
     if (i % 2) {
-      odd += FXSYS_atoi(contents.Mid(i - 1, 1).c_str());
+      odd += FXSYS_DecimalCharToInt(contents[i - 1]);
     } else {
-      even += FXSYS_atoi(contents.Mid(i - 1, 1).c_str());
+      even += FXSYS_DecimalCharToInt(contents[i - 1]);
     }
   }
   int32_t checksum = (odd * 3 + even) % 10;
@@ -124,7 +125,7 @@
 
   int32_t i = 0;
   for (i = 0; i <= 3; i++) {
-    int32_t digit = FXSYS_atoi(contents.Mid(i, 1).c_str());
+    int32_t digit = FXSYS_DecimalCharToInt(contents[i]);
     pos += AppendPattern(result.get(), pos, L_PATTERNS[digit], 4, 0, e);
     if (e != BCExceptionNO)
       return nullptr;
@@ -134,7 +135,7 @@
     return nullptr;
 
   for (i = 4; i <= 7; i++) {
-    int32_t digit = FXSYS_atoi(contents.Mid(i, 1).c_str());
+    int32_t digit = FXSYS_DecimalCharToInt(contents[i]);
     pos += AppendPattern(result.get(), pos, L_PATTERNS[digit], 4, 1, e);
     if (e != BCExceptionNO)
       return nullptr;
diff --git a/fxbarcode/oned/BC_OnedUPCAWriter.cpp b/fxbarcode/oned/BC_OnedUPCAWriter.cpp
index 5782fe4..fac4a1b 100644
--- a/fxbarcode/oned/BC_OnedUPCAWriter.cpp
+++ b/fxbarcode/oned/BC_OnedUPCAWriter.cpp
@@ -24,6 +24,7 @@
 
 #include <vector>
 
+#include "core/fxcrt/fx_extension.h"
 #include "core/fxge/cfx_defaultrenderdevice.h"
 #include "fxbarcode/BC_Writer.h"
 #include "fxbarcode/oned/BC_OneDimWriter.h"
@@ -72,9 +73,9 @@
   FX_STRSIZE j = 1;
   for (FX_STRSIZE i = contents.GetLength(); i > 0; i--) {
     if (j % 2) {
-      odd += FXSYS_atoi(contents.Mid(i - 1, 1).c_str());
+      odd += FXSYS_DecimalCharToInt(contents[i - 1]);
     } else {
-      even += FXSYS_atoi(contents.Mid(i - 1, 1).c_str());
+      even += FXSYS_DecimalCharToInt(contents[i - 1]);
     }
     j++;
   }
diff --git a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp b/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
index b02efbb..b80100a 100644
--- a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
+++ b/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
@@ -170,7 +170,7 @@
         return pNode;
     } else if (bNewExprStyle) {
       CFX_WideString wsProcessedTarget = wsExpr;
-      if (wsExpr.Left(4) == L"som(" && wsExpr.Right(1) == L")") {
+      if (wsExpr.Left(4) == L"som(" && wsExpr.Last() == L')') {
         wsProcessedTarget = wsExpr.Mid(4, wsExpr.GetLength() - 5);
       }
       XFA_RESOLVENODE_RS rs;
diff --git a/xfa/fxfa/parser/cxfa_resolveprocessor.cpp b/xfa/fxfa/parser/cxfa_resolveprocessor.cpp
index fe4605b..15c3f14 100644
--- a/xfa/fxfa/parser/cxfa_resolveprocessor.cpp
+++ b/xfa/fxfa/parser/cxfa_resolveprocessor.cpp
@@ -661,9 +661,9 @@
   ASSERT(iFoundCount == pdfium::CollectionSize<int32_t>(rnd.m_Objects));
   CFX_WideString wsExpression;
   XFA_SCRIPTLANGTYPE eLangType = XFA_SCRIPTLANGTYPE_Unkown;
-  if (wsCondition.Left(2) == L".[" && wsCondition.Right(1) == L"]") {
+  if (wsCondition.Left(2) == L".[" && wsCondition.Last() == L']') {
     eLangType = XFA_SCRIPTLANGTYPE_Formcalc;
-  } else if (wsCondition.Left(2) == L".(" && wsCondition.Right(1) == L")") {
+  } else if (wsCondition.Left(2) == L".(" && wsCondition.Last() == L')') {
     eLangType = XFA_SCRIPTLANGTYPE_Javascript;
   } else {
     return;