summaryrefslogtreecommitdiff
path: root/source/util
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-20 01:51:05 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-20 01:51:05 +0200
commit40d9a1d5c3e85486aea964c1446402a3be6ec05a (patch)
tree7af82c46a459afc99156e5a6022946b43e35a3de /source/util
parentbc228753bfb4a2faea540cddb20fc39ebd265db5 (diff)
feat(import): parse otpauth URIs and unencrypted Aegis JSON in resumable steps
Streaming JSON tokenizer with depth and length limits and native skipping of long strings; Aegis reader for database versions 1-3 with groups and encrypted-export detection; otpauth parser with ';' separators and Steam; import job with Replace mode, duplicate and replacement checks, a sealed multi-part buffer and a report. Google Authenticator exports deferred. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/util')
-rw-r--r--source/util/Text.mc56
1 files changed, 56 insertions, 0 deletions
diff --git a/source/util/Text.mc b/source/util/Text.mc
new file mode 100644
index 0000000..9af7b32
--- /dev/null
+++ b/source/util/Text.mc
@@ -0,0 +1,56 @@
+// Author: cirakg & claude ai
+// Summary: Small string helpers for parsing: trimming, clipping for messages, integer parsing, case-insensitive search.
+
+import Toybox.Lang;
+
+module Text {
+
+ // Text without leading and trailing spaces, tabs and line breaks.
+ function trim(text as String) as String {
+ var chars = text.toCharArray();
+ var start = 0;
+ var end = chars.size();
+ while (start < end && isSpace(chars[start])) {
+ start++;
+ }
+ while (end > start && isSpace(chars[end - 1])) {
+ end--;
+ }
+ return start == 0 && end == chars.size() ? text : text.substring(start, end) as String;
+ }
+
+ function isSpace(c as Char) as Boolean {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ }
+
+ // At most maxChars characters, with "…" when shortened (for messages that
+ // quote user input).
+ function clip(text as String, maxChars as Number) as String {
+ return text.length() <= maxChars ? text : (text.substring(0, maxChars) as String) + "…";
+ }
+
+ // A non-negative decimal integer (at most 18 digits), or null.
+ function parseLong(text as String) as Long? {
+ var chars = text.toCharArray();
+ if (chars.size() == 0 || chars.size() > 18) {
+ return null;
+ }
+ var value = 0l;
+ for (var i = 0; i < chars.size(); i++) {
+ var c = chars[i];
+ if (c < '0' || c > '9') {
+ return null;
+ }
+ value = value * 10 + (c.toNumber() - 48);
+ }
+ return value;
+ }
+
+ // Index of needle in haystack ignoring ASCII case, from `from`, or -1.
+ function findIgnoreCase(haystack as String, needle as String, from as Number) as Number {
+ var lower = haystack.toLower();
+ var rest = from == 0 ? lower : lower.substring(from, lower.length()) as String;
+ var at = rest.find(needle.toLower());
+ return at == null ? -1 : at + from;
+ }
+}