Convert some {Byte,Wide}String::Last() calls to Substr().

Gemini generated patch once human realized that many of these
less-readable expressions abound.

Change-Id: Id0baf48847395be56b15f0e4187bdeecd91b3fd4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/145830
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
index aced8c3..c498bf5 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -296,8 +296,7 @@
   ByteString mid_string = text_string.Substr(
       first_resource_at.value(),
       second_resource_at.value() - first_resource_at.value());
-  ByteString last_string =
-      text_string.Last(text_string.GetLength() - second_resource_at.value());
+  ByteString last_string = text_string.Substr(second_resource_at.value());
   // q and Q must be outside the BT .. ET operations
   const ByteString kCompareString1 =
       "q .5 .69999999 .34999999 rg 1 .89999998 0 RG /";
@@ -378,8 +377,7 @@
   ASSERT_TRUE(first_resource_at.has_value());
   first_resource_at = first_resource_at.value() + 1;
   ByteString first_string = text_string.First(first_resource_at.value());
-  ByteString last_string =
-      text_string.Last(text_string.GetLength() - first_resource_at.value());
+  ByteString last_string = text_string.Substr(first_resource_at.value());
   // q and Q must be outside the BT .. ET operations
   ByteString compare_string1 = "q 0 0 5 4 re W* n BT /";
   ByteString compare_string2 =
diff --git a/core/fpdfapi/font/cpdf_cmapparser.cpp b/core/fpdfapi/font/cpdf_cmapparser.cpp
index e6f018c..87b376e 100644
--- a/core/fpdfapi/font/cpdf_cmapparser.cpp
+++ b/core/fpdfapi/font/cpdf_cmapparser.cpp
@@ -23,7 +23,7 @@
   if (word.GetLength() <= 2) {
     return ByteStringView();
   }
-  return word.Last(word.GetLength() - 2);
+  return word.Substr(2);
 }
 
 }  // namespace
diff --git a/core/fpdfapi/font/cpdf_fontglobals.cpp b/core/fpdfapi/font/cpdf_fontglobals.cpp
index bd57de4..65eaf38 100644
--- a/core/fpdfapi/font/cpdf_fontglobals.cpp
+++ b/core/fpdfapi/font/cpdf_fontglobals.cpp
@@ -25,7 +25,7 @@
 
 RetainPtr<const CPDF_CMap> LoadPredefinedCMap(ByteStringView name) {
   if (!name.IsEmpty() && name[0] == '/') {
-    name = name.Last(name.GetLength() - 1);
+    name = name.Substr(1);
   }
   return pdfium::MakeRetain<CPDF_CMap>(name);
 }
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index 2fda3c2..8477f71 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -663,7 +663,7 @@
     }
     // Next `syntax_` read below may invalidate `word`. Must save to `key`.
     ByteStringView word = syntax_->GetWord();
-    ByteString key(word.Last(word.GetLength() - 1));
+    ByteString key(word.Substr(1));
     auto pObj = syntax_->ReadNextObject(false, false, 0);
     if (pObj && !pObj->IsInline()) {
       dict->SetNewFor<CPDF_Reference>(key, document_, pObj->GetObjNum());
@@ -1266,7 +1266,7 @@
 
   if (name == "DeviceGray" || name == "DeviceCMYK" || name == "DeviceRGB") {
     ByteString defname = "Default";
-    defname += name.Last(name.GetLength() - 7);
+    defname += name.Substr(7);
     RetainPtr<const CPDF_Object> pDefObj =
         FindResourceObj("ColorSpace", defname);
     if (!pDefObj) {
@@ -1680,7 +1680,7 @@
         break;
       case CPDF_StreamParser::ElementType::kName: {
         auto word = syntax_->GetWord();
-        AddNameParam(word.Last(word.GetLength() - 1));
+        AddNameParam(word.Substr(1));
         break;
       }
       default:
diff --git a/core/fxcrt/css/cfx_cssselector.cpp b/core/fxcrt/css/cfx_cssselector.cpp
index 3f829d1..0d25cbf 100644
--- a/core/fxcrt/css/cfx_cssselector.cpp
+++ b/core/fxcrt/css/cfx_cssselector.cpp
@@ -62,7 +62,7 @@
     if (head) {
       head->set_is_descendant();
     }
-    size_t len = is_star ? 1 : GetCSSNameLen(str.Last(str.GetLength() - i));
+    size_t len = is_star ? 1 : GetCSSNameLen(str.Substr(i));
     auto new_head =
         std::make_unique<CFX_CSSSelector>(str.Substr(i, len), std::move(head));
     head = std::move(new_head);
diff --git a/core/fxcrt/fx_string.h b/core/fxcrt/fx_string.h
index 06ebe3a..fd5a6ad 100644
--- a/core/fxcrt/fx_string.h
+++ b/core/fxcrt/fx_string.h
@@ -45,7 +45,7 @@
       break;
     }
     result.emplace_back(remaining.First(index.value()));
-    remaining = remaining.Last(remaining.GetLength() - index.value() - 1);
+    remaining = remaining.Substr(index.value() + 1);
   }
   result.emplace_back(remaining);
   return result;
diff --git a/core/fxcrt/xml/cfx_xmlelement.cpp b/core/fxcrt/xml/cfx_xmlelement.cpp
index 185bd93..00c5757 100644
--- a/core/fxcrt/xml/cfx_xmlelement.cpp
+++ b/core/fxcrt/xml/cfx_xmlelement.cpp
@@ -39,8 +39,7 @@
 
 WideString CFX_XMLElement::GetLocalTagName() const {
   auto pos = name_.Find(L':');
-  return pos.has_value() ? name_.Last(name_.GetLength() - pos.value() - 1)
-                         : name_;
+  return pos.has_value() ? name_.Substr(pos.value() + 1) : name_;
 }
 
 WideString CFX_XMLElement::GetNamespacePrefix() const {
diff --git a/core/fxge/cfx_fontmapper.cpp b/core/fxge/cfx_fontmapper.cpp
index 2ebf53e..f1ec184 100644
--- a/core/fxge/cfx_fontmapper.cpp
+++ b/core/fxge/cfx_fontmapper.cpp
@@ -654,7 +654,7 @@
     if (pos.has_value()) {
       family = subst_name.First(pos.value());
       GetStandardFontName(&family);
-      style = subst_name.Last(subst_name.GetLength() - (pos.value() + 1));
+      style = subst_name.Substr(pos.value() + 1);
       has_comma = true;
     } else {
       family = subst_name;
@@ -677,7 +677,7 @@
     if (!has_comma) {
       std::optional<size_t> pos = family.ReverseFind('-');
       if (pos.has_value()) {
-        style = family.Last(family.GetLength() - (pos.value() + 1));
+        style = family.Substr(pos.value() + 1);
         family = family.First(pos.value());
         has_hyphen = true;
       }
diff --git a/fxjs/cjs_publicmethods.cpp b/fxjs/cjs_publicmethods.cpp
index 365336d..06f1d39 100644
--- a/fxjs/cjs_publicmethods.cpp
+++ b/fxjs/cjs_publicmethods.cpp
@@ -130,7 +130,7 @@
   WideString postfix;
   int end = event->SelEnd();
   if (end >= 0 && static_cast<size_t>(end) < value.GetLength()) {
-    postfix = value.Last(value.GetLength() - static_cast<size_t>(end));
+    postfix = value.Substr(static_cast<size_t>(end));
   }
   return prefix + change + postfix;
 }
diff --git a/fxjs/cjs_util.cpp b/fxjs/cjs_util.cpp
index bbf83b2..2c33ea7 100644
--- a/fxjs/cjs_util.cpp
+++ b/fxjs/cjs_util.cpp
@@ -120,7 +120,7 @@
           unsafe_fmt_string.Find(L"%", offset + 1);
       if (!offset_end.has_value()) {
         unsafe_conversion_specifiers.push_back(
-            unsafe_fmt_string.Last(unsafe_fmt_string.GetLength() - offset));
+            unsafe_fmt_string.Substr(offset));
         break;
       }
 
@@ -161,8 +161,7 @@
   // Remove the 'S' sentinel introduced earlier.
   DCHECK_EQ(L'S', result[0]);
   auto result_view = result.AsStringView();
-  return CJS_Result::Success(
-      pRuntime->NewString(result_view.Last(result_view.GetLength() - 1)));
+  return CJS_Result::Success(pRuntime->NewString(result_view.Substr(1)));
 }
 
 CJS_Result CJS_Util::printd(CJS_Runtime* pRuntime,
diff --git a/fxjs/xfa/cfxjse_engine.cpp b/fxjs/xfa/cfxjse_engine.cpp
index 117f75c..a7725a6 100644
--- a/fxjs/xfa/cfxjse_engine.cpp
+++ b/fxjs/xfa/cfxjse_engine.cpp
@@ -497,7 +497,7 @@
 
   if (pObject->IsNode()) {
     if (wsPropNameView[0] == '#') {
-      wsPropNameView = wsPropNameView.Last(wsPropNameView.GetLength() - 1);
+      wsPropNameView = wsPropNameView.Substr(1);
     }
 
     CXFA_Node* pNode = ToNode(pObject);
diff --git a/fxjs/xfa/cfxjse_formcalc_context.cpp b/fxjs/xfa/cfxjse_formcalc_context.cpp
index e2f4ab2..74bbeea 100644
--- a/fxjs/xfa/cfxjse_formcalc_context.cpp
+++ b/fxjs/xfa/cfxjse_formcalc_context.cpp
@@ -1797,7 +1797,7 @@
     info.GetReturnValue().Set(0);
     return;
   }
-  bsArg = bsArg.Last(bsArg.GetLength() - (pos.value() + 1));
+  bsArg = bsArg.Substr(pos.value() + 1);
 
   CXFA_LocaleValue timeValue(CXFA_LocaleValue::ValueType::kTime,
                              WideString::FromUTF8(bsArg.AsStringView()), pMgr);
@@ -3584,8 +3584,7 @@
         wsDatePattern += wsPattern.First(iTChar.value()) + L"} ";
 
         auto wsTimePattern = WideString::FromASCII("time{");
-        wsTimePattern +=
-            wsPattern.Last(wsPattern.GetLength() - (iTChar.value() + 1)) + L"}";
+        wsTimePattern += wsPattern.Substr(iTChar.value() + 1) + L"}";
         wsPattern = wsDatePattern + wsTimePattern;
       } break;
       case CXFA_LocaleValue::ValueType::kDate: {
@@ -3770,9 +3769,8 @@
       }
       WideString wsDatePattern(L"date{" + wsPattern.First(iTChar.value()) +
                                L"} ");
-      WideString wsTimePattern(
-          L"time{" +
-          wsPattern.Last(wsPattern.GetLength() - (iTChar.value() + 1)) + L"}");
+      WideString wsTimePattern(L"time{" + wsPattern.Substr(iTChar.value() + 1) +
+                               L"}");
       wsPattern = wsDatePattern + wsTimePattern;
       CXFA_LocaleValue localeValue(dwPatternType, wsValue, wsPattern, pLocale,
                                    pMgr);
diff --git a/fxjs/xfa/cfxjse_nodehelper.cpp b/fxjs/xfa/cfxjse_nodehelper.cpp
index 208c69c..9ad6105 100644
--- a/fxjs/xfa/cfxjse_nodehelper.cpp
+++ b/fxjs/xfa/cfxjse_nodehelper.cpp
@@ -61,13 +61,13 @@
   bool bIsClassName = false;
   bool bResult = false;
   if (!wsNameView.IsEmpty() && wsNameView[0] == '!') {
-    wsNameView = wsNameView.Last(wsNameView.GetLength() - 1);
+    wsNameView = wsNameView.Substr(1);
     create_parent_ = ToNode(
         pScriptContext->GetDocument()->GetXFAObject(XFA_HASHCODE_Datasets));
   }
   if (!wsNameView.IsEmpty() && wsNameView[0] == '#') {
     bIsClassName = true;
-    wsNameView = wsNameView.Last(wsNameView.GetLength() - 1);
+    wsNameView = wsNameView.Substr(1);
   }
   if (wsNameView.IsEmpty()) {
     return false;
diff --git a/fxjs/xfa/cfxjse_resolveprocessor.cpp b/fxjs/xfa/cfxjse_resolveprocessor.cpp
index cc900cb..9c76c6b 100644
--- a/fxjs/xfa/cfxjse_resolveprocessor.cpp
+++ b/fxjs/xfa/cfxjse_resolveprocessor.cpp
@@ -104,10 +104,9 @@
   WideStringView wsName = rnd.name_.AsStringView();
   WideString wsCondition = rnd.condition_;
   const bool bClassName = !wsName.IsEmpty() && wsName[0] == '#';
-  CXFA_Node* const pChild =
-      bClassName
-          ? pParent->GetOneChildOfClass(wsName.Last(wsName.GetLength() - 1))
-          : pParent->GetOneChildNamed(wsName);
+  CXFA_Node* const pChild = bClassName
+                                ? pParent->GetOneChildOfClass(wsName.Substr(1))
+                                : pParent->GetOneChildNamed(wsName);
   if (!pChild) {
     return false;
   }
diff --git a/fxjs/xfa/cjx_instancemanager.cpp b/fxjs/xfa/cjx_instancemanager.cpp
index c553a54..e721773 100644
--- a/fxjs/xfa/cjx_instancemanager.cpp
+++ b/fxjs/xfa/cjx_instancemanager.cpp
@@ -62,10 +62,9 @@
 
   if (iDesired < iCount) {
     WideString wsInstManagerName = GetCData(XFA_Attribute::Name);
-    WideString wsInstanceName = WideString(
-        wsInstManagerName.IsEmpty()
-            ? wsInstManagerName
-            : wsInstManagerName.Last(wsInstManagerName.GetLength() - 1));
+    WideString wsInstanceName =
+        WideString(wsInstManagerName.IsEmpty() ? wsInstManagerName
+                                               : wsInstManagerName.Substr(1));
     uint32_t dInstanceNameHash =
         FX_HashCode_GetW(wsInstanceName.AsStringView());
     CXFA_Node* pPrevSibling = iDesired == 0
diff --git a/fxjs/xfa/cjx_subform.cpp b/fxjs/xfa/cjx_subform.cpp
index 89b328e..67aa28d 100644
--- a/fxjs/xfa/cjx_subform.cpp
+++ b/fxjs/xfa/cjx_subform.cpp
@@ -126,7 +126,7 @@
       WideString wsInstMgrName =
           pNode->JSObject()->GetCData(XFA_Attribute::Name);
       if (wsInstMgrName.GetLength() >= 1 && wsInstMgrName[0] == '_' &&
-          wsInstMgrName.Last(wsInstMgrName.GetLength() - 1) == wsName) {
+          wsInstMgrName.Substr(1) == wsName) {
         pInstanceMgr = pNode;
       }
       break;
diff --git a/xfa/fgas/crt/cfgas_stringformatter.cpp b/xfa/fgas/crt/cfgas_stringformatter.cpp
index 2f9a244..09b9095 100644
--- a/xfa/fgas/crt/cfgas_stringformatter.cpp
+++ b/xfa/fgas/crt/cfgas_stringformatter.cpp
@@ -1725,7 +1725,7 @@
              pattern_span_[ccf] != '.' && pattern_span_[ccf] != '(') {
         if (pattern_span_[ccf] == 'T') {
           *wsDatePattern = pattern_.First(ccf);
-          *wsTimePattern = pattern_.Last(pattern_.GetLength() - ccf);
+          *wsTimePattern = pattern_.Substr(ccf);
           wsTimePattern->SetAt(0, ' ');
           if (!*pLocale) {
             *pLocale = pLocaleMgr->GetDefLocale();
diff --git a/xfa/fxfa/cxfa_eventparam.cpp b/xfa/fxfa/cxfa_eventparam.cpp
index b77fc56..1edd1c7 100644
--- a/xfa/fxfa/cxfa_eventparam.cpp
+++ b/xfa/fxfa/cxfa_eventparam.cpp
@@ -19,6 +19,5 @@
     default;
 
 WideString CXFA_EventParam::GetNewText() const {
-  return prev_text_.First(sel_start_) + change_ +
-         prev_text_.Last(prev_text_.GetLength() - sel_end_);
+  return prev_text_.First(sel_start_) + change_ + prev_text_.Substr(sel_end_);
 }
diff --git a/xfa/fxfa/formcalc/cxfa_fmexpression.cpp b/xfa/fxfa/formcalc/cxfa_fmexpression.cpp
index b2ae623..8f55dbe 100644
--- a/xfa/fxfa/formcalc/cxfa_fmexpression.cpp
+++ b/xfa/fxfa/formcalc/cxfa_fmexpression.cpp
@@ -79,7 +79,7 @@
   if (ident.IsEmpty() || ident[0] != L'!') {
     return ident;
   }
-  return L"pfm__excl__" + ident.Last(ident.GetLength() - 1);
+  return L"pfm__excl__" + ident.Substr(1);
 }
 
 }  // namespace
@@ -211,7 +211,7 @@
   } else if (identifier_.EqualsASCII("$template")) {
     *js << "xfa.template";
   } else if (identifier_[0] == L'!') {
-    *js << "pfm__excl__" << identifier_.Last(identifier_.GetLength() - 1);
+    *js << "pfm__excl__" << identifier_.Substr(1);
   } else {
     *js << identifier_;
   }
diff --git a/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp b/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp
index 57a3ed0..6a1f607 100644
--- a/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp
+++ b/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp
@@ -201,7 +201,7 @@
     if (wsExpr[0] == '#') {
       CXFA_Node* pNode = document->GetNodeByID(
           ToNode(document->GetXFAObject(XFA_HASHCODE_Template)),
-          wsExpr.Last(wsExpr.GetLength() - 1).AsStringView());
+          wsExpr.Substr(1).AsStringView());
       if (pNode) {
         return pNode;
       }
diff --git a/xfa/fxfa/parser/cxfa_document_builder.cpp b/xfa/fxfa/parser/cxfa_document_builder.cpp
index 9265091..8449608 100644
--- a/xfa/fxfa/parser/cxfa_document_builder.cpp
+++ b/xfa/fxfa/parser/cxfa_document_builder.cpp
@@ -75,7 +75,7 @@
     wsLocalAttrName = std::move(wsAttrName);
     return false;
   }
-  wsLocalAttrName = wsAttrName.Last(wsAttrName.GetLength() - pos.value() - 1);
+  wsLocalAttrName = wsAttrName.Substr(pos.value() + 1);
   return true;
 }
 
diff --git a/xfa/fxfa/parser/cxfa_localevalue.cpp b/xfa/fxfa/parser/cxfa_localevalue.cpp
index 7fd3738..e9ed66e 100644
--- a/xfa/fxfa/parser/cxfa_localevalue.cpp
+++ b/xfa/fxfa/parser/cxfa_localevalue.cpp
@@ -67,7 +67,7 @@
   }
 
   wsDate = wsDateTime.First(nSplitIndex.value());
-  wsTime = wsDateTime.Last(wsDateTime.GetLength() - nSplitIndex.value() - 1);
+  wsTime = wsDateTime.Substr(nSplitIndex.value() + 1);
   return true;
 }
 
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index dbedaf1..7b4ced5 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -549,7 +549,7 @@
       return false;
     }
   }
-  wsTime = wsDateTime.Last(wsDateTime.GetLength() - nSplitIndex.value() - 1);
+  wsTime = wsDateTime.Substr(nSplitIndex.value() + 1);
   if (!wsTime.IsEmpty()) {
     if (!std::any_of(wsTime.begin(), wsTime.end(),
                      [](wchar_t c) { return FXSYS_IsDecimalDigit(c); })) {
@@ -685,7 +685,7 @@
   }
   if (dot_index < wsSrcNum.GetLength()) {
     wsOutput += pLocale->GetDecimalSymbol();
-    wsOutput += wsSrcNum.Last(wsSrcNum.GetLength() - dot_index - 1);
+    wsOutput += wsSrcNum.Substr(dot_index + 1);
   }
   if (bNeg) {
     return pLocale->GetMinusSymbol() + wsOutput;
@@ -1895,7 +1895,7 @@
         WideString wsInstName =
             pNode->JSObject()->GetCData(XFA_Attribute::Name);
         if (wsInstName.GetLength() > 0 && wsInstName[0] == '_' &&
-            wsInstName.Last(wsInstName.GetLength() - 1) == wsName) {
+            wsInstName.Substr(1) == wsName) {
           pInstanceMgr = pNode;
         }
         break;
@@ -1988,7 +1988,7 @@
       WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
       WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
       if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
-          wsInstName.Last(wsInstName.GetLength() - 1) != wsName) {
+          wsInstName.Substr(1) != wsName) {
         return nullptr;
       }
       dwNameHash = pNode->GetNameHash();
@@ -2022,7 +2022,7 @@
       WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
       WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
       if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
-          wsInstName.Last(wsInstName.GetLength() - 1) != wsName) {
+          wsInstName.Substr(1) != wsName) {
         return iCount;
       }
       dwNameHash = pNode->GetNameHash();