-
Notifications
You must be signed in to change notification settings - Fork 0
Harden AppleScript JSON output with runtime escaping #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,69 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Foundation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Shared AppleScript escape handlers and Swift-side JSON safety net. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| enum JsonEscape { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // MARK: - AppleScript Handlers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// AppleScript handlers that escape string values for safe JSON embedding. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Appended to every template script by AppleScriptRunner. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// `jsonEsc(s)` escapes: \ → \\, " → \", CR → \n, LF → \n, tab → \t | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// `replaceText(theString, old, new)` helper for text item delimiter-based replacement. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| static let handlers: String = #""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| on jsonEsc(s) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set s to s as text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set s to my replaceText(s, "\\", "\\\\") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set s to my replaceText(s, "\"", "\\" & quote) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set s to my replaceText(s, return, "\\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set s to my replaceText(s, linefeed, "\\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set s to my replaceText(s, tab, "\\t") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+11
to
+21
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// `jsonEsc(s)` escapes: \ → \\, " → \", CR → \n, LF → \n, tab → \t | |
| /// `replaceText(theString, old, new)` helper for text item delimiter-based replacement. | |
| static let handlers: String = #""" | |
| on jsonEsc(s) | |
| set s to s as text | |
| set s to my replaceText(s, "\\", "\\\\") | |
| set s to my replaceText(s, "\"", "\\" & quote) | |
| set s to my replaceText(s, return, "\\n") | |
| set s to my replaceText(s, linefeed, "\\n") | |
| set s to my replaceText(s, tab, "\\t") | |
| /// `jsonEsc(s)` escapes: \ → \\, " → \", CR → \n, LF → \n, tab → \t, backspace → \b, form feed → \f, | |
| /// and other control characters U+0000–U+0008, U+000B, U+000E–U+001F to \u00XX. | |
| /// `replaceText(theString, old, new)` helper for text item delimiter-based replacement. | |
| static let handlers: String = #""" | |
| on jsonEsc(s) | |
| set s to s as text | |
| -- Basic JSON escapes | |
| set s to my replaceText(s, "\\", "\\\\") | |
| set s to my replaceText(s, "\"", "\\" & quote) | |
| set s to my replaceText(s, return, "\\n") | |
| set s to my replaceText(s, linefeed, "\\n") | |
| set s to my replaceText(s, tab, "\\t") | |
| -- Additional JSON control characters | |
| set s to my replaceText(s, character id 8, "\\b") -- backspace | |
| set s to my replaceText(s, character id 12, "\\f") -- form feed | |
| -- Remaining control chars (U+0000–U+0007, U+000B, U+000E–U+001F) as \u00XX | |
| set s to my replaceText(s, character id 0, "\\u0000") | |
| set s to my replaceText(s, character id 1, "\\u0001") | |
| set s to my replaceText(s, character id 2, "\\u0002") | |
| set s to my replaceText(s, character id 3, "\\u0003") | |
| set s to my replaceText(s, character id 4, "\\u0004") | |
| set s to my replaceText(s, character id 5, "\\u0005") | |
| set s to my replaceText(s, character id 6, "\\u0006") | |
| set s to my replaceText(s, character id 7, "\\u0007") | |
| set s to my replaceText(s, character id 11, "\\u000B") | |
| set s to my replaceText(s, character id 14, "\\u000E") | |
| set s to my replaceText(s, character id 15, "\\u000F") | |
| set s to my replaceText(s, character id 16, "\\u0010") | |
| set s to my replaceText(s, character id 17, "\\u0011") | |
| set s to my replaceText(s, character id 18, "\\u0012") | |
| set s to my replaceText(s, character id 19, "\\u0013") | |
| set s to my replaceText(s, character id 20, "\\u0014") | |
| set s to my replaceText(s, character id 21, "\\u0015") | |
| set s to my replaceText(s, character id 22, "\\u0016") | |
| set s to my replaceText(s, character id 23, "\\u0017") | |
| set s to my replaceText(s, character id 24, "\\u0018") | |
| set s to my replaceText(s, character id 25, "\\u0019") | |
| set s to my replaceText(s, character id 26, "\\u001A") | |
| set s to my replaceText(s, character id 27, "\\u001B") | |
| set s to my replaceText(s, character id 28, "\\u001C") | |
| set s to my replaceText(s, character id 29, "\\u001D") | |
| set s to my replaceText(s, character id 30, "\\u001E") | |
| set s to my replaceText(s, character id 31, "\\u001F") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
jsonEschandler escapes carriage return (CR/return) as\non line 19, but JSON spec requires it to be escaped as\r. This creates incorrect JSON output for strings containing CR characters. Change line 19 to:set s to my replaceText(s, return, "\\r")