mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2026-03-27 19:37:22 +01:00
Add files via upload
This commit is contained in:
189
json-parser
Normal file
189
json-parser
Normal file
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function output_entry() {
|
||||
echo "$1=$2"
|
||||
}
|
||||
|
||||
function parse_array() {
|
||||
local current_path="${1:+$1.}$2"
|
||||
local current_scope="root"
|
||||
local current_index=0
|
||||
|
||||
while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
|
||||
[ "$preserve_current_char" == "0" ] && chars_read=$((chars_read+1)) && read -r -s -n 1 c
|
||||
preserve_current_char=0
|
||||
c=${c:-' '}
|
||||
|
||||
case "$current_scope" in
|
||||
"root") # Waiting for new object or value
|
||||
case "$c" in
|
||||
'{')
|
||||
parse_object "$current_path" "$current_index"
|
||||
current_scope="entry_separator"
|
||||
;;
|
||||
']')
|
||||
return
|
||||
;;
|
||||
[\"tfTF\-0-9])
|
||||
preserve_current_char=1 # Let the parse value function decide what kind of value this is
|
||||
parse_value "$current_path" "$current_index"
|
||||
preserve_current_char=1 # Parse value has terminated with a separator or an array end, but we can handle this only in the next while iteration
|
||||
current_scope="entry_separator"
|
||||
;;
|
||||
|
||||
esac
|
||||
;;
|
||||
"entry_separator")
|
||||
[ "$c" == "," ] && current_index=$((current_index+1)) && current_scope="root"
|
||||
[ "$c" == "]" ] && return
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
function parse_value() {
|
||||
local current_path="${1:+$1.}$2"
|
||||
local current_scope="root"
|
||||
|
||||
while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
|
||||
[ "$preserve_current_char" == "0" ] && chars_read=$((chars_read+1)) && read -r -s -n 1 c
|
||||
preserve_current_char=0
|
||||
c=${c:-' '}
|
||||
|
||||
case "$current_scope" in
|
||||
"root") # Waiting for new string, number or boolean
|
||||
case "$c" in
|
||||
'"') # String begin
|
||||
current_scope="string"
|
||||
current_varvalue=""
|
||||
;;
|
||||
[\-0-9]) # Number begin
|
||||
current_scope="number"
|
||||
current_varvalue="$c"
|
||||
;;
|
||||
[tfTF]) # True or false begin
|
||||
current_scope="boolean"
|
||||
current_varvalue="$c"
|
||||
;;
|
||||
"[") # Array begin
|
||||
parse_array "" "$current_path"
|
||||
return
|
||||
;;
|
||||
"{") # Object begin
|
||||
parse_object "" "$current_path"
|
||||
return
|
||||
esac
|
||||
;;
|
||||
"string") # Waiting for string end
|
||||
case "$c" in
|
||||
'"') # String end if not in escape mode, normal character otherwise
|
||||
[ "$current_escaping" == "0" ] && output_entry "$current_path" "$current_varvalue" && return
|
||||
[ "$current_escaping" == "1" ] && current_varvalue="$current_varvalue$c" && current_escaping=0
|
||||
;;
|
||||
'\') # Escape character, entering or leaving escape mode
|
||||
current_escaping=$((1-current_escaping))
|
||||
current_varvalue="$current_varvalue$c"
|
||||
;;
|
||||
*) # Any other string character
|
||||
current_escaping=0
|
||||
current_varvalue="$current_varvalue$c"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"number") # Waiting for number end
|
||||
case "$c" in
|
||||
[,\]}]) # Separator or array end or object end
|
||||
output_entry "$current_path" "$current_varvalue"
|
||||
preserve_current_char=1 # The caller needs to handle this char
|
||||
return
|
||||
;;
|
||||
[\-0-9.]) # Number can only contain digits, dots and a sign
|
||||
current_varvalue="$current_varvalue$c"
|
||||
;;
|
||||
# Ignore everything else
|
||||
esac
|
||||
;;
|
||||
"boolean") # Waiting for boolean to end
|
||||
case "$c" in
|
||||
[,\]}]) # Separator or array end or object end
|
||||
output_entry "$current_path" "$current_varvalue"
|
||||
preserve_current_char=1 # The caller needs to handle this char
|
||||
return
|
||||
;;
|
||||
[a-zA-Z]) # No need to do some strict checking, we do not want to validate the incoming json data
|
||||
current_varvalue="$current_varvalue$c"
|
||||
;;
|
||||
# Ignore everything else
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
function parse_object() {
|
||||
local current_path="${1:+$1.}$2"
|
||||
local current_scope="root"
|
||||
|
||||
while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
|
||||
[ "$preserve_current_char" == "0" ] && chars_read=$((chars_read+1)) && read -r -s -n 1 c
|
||||
preserve_current_char=0
|
||||
c=${c:-' '}
|
||||
|
||||
case "$current_scope" in
|
||||
"root") # Waiting for new field or object end
|
||||
[ "$c" == "}" ] && return
|
||||
[ "$c" == "\"" ] && current_scope="varname" && current_varname="" && current_escaping=0
|
||||
;;
|
||||
"varname") # Reading the field name
|
||||
case "$c" in
|
||||
'"') # String end if not in escape mode, normal character otherwise
|
||||
[ "$current_escaping" == "0" ] && current_scope="key_value_separator"
|
||||
[ "$current_escaping" == "1" ] && current_varname="$current_varname$c"
|
||||
;;
|
||||
'\') # Escape character, entering or leaving escape mode
|
||||
current_escaping=$((1-current_escaping))
|
||||
current_varname="$current_varname$c"
|
||||
;;
|
||||
*) # Any other string character
|
||||
current_escaping=0
|
||||
current_varname="$current_varname$c"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
"key_value_separator") # Waiting for the key value separator (:)
|
||||
[ "$c" == ":" ] && parse_value "$current_path" "$current_varname" && current_scope="field_separator"
|
||||
;;
|
||||
"field_separator") # Waiting for the field separator (,)
|
||||
[ "$c" == ',' ] && current_scope="root"
|
||||
[ "$c" == '}' ] && return
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
function parse() {
|
||||
chars_read=0
|
||||
preserve_current_char=0
|
||||
|
||||
while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do
|
||||
read -r -s -n 1 c
|
||||
c=${c:-' '}
|
||||
chars_read=$((chars_read+1))
|
||||
|
||||
# A valid JSON string consists of exactly one object
|
||||
[ "$c" == "{" ] && parse_object "" "" && return
|
||||
# ... or one array
|
||||
[ "$c" == "[" ] && parse_array "" "" && return
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
if [ -z "$@" ]; then
|
||||
INPUT=$(cat -)
|
||||
else
|
||||
INPUT=$(echo "$@")
|
||||
fi
|
||||
|
||||
INPUT_LENGTH="${#INPUT}"
|
||||
parse "" "" <<< "${INPUT}"
|
||||
|
||||
Reference in New Issue
Block a user