REBOL [
Title: "REBOL Web Form Encoder/Decoder"
Author: "Christopher Ross-Gill"
Date: 30-Aug-2013
Version: 0.2.0
Purpose: "Convert a Rebol block to a URL-Encoded Web Form string"
Comment: "Conforms to application/x-www-form-urlencoded"
Home: http://www.ross-gill.com/page/RFC_Web_Forms_and_Rebol
File: %altwebform.r
Type: 'module
Exports: [url-decode url-encode load-webform to-webform]
Example: [
"a=3&aa.a=1&b.c.=1&b.c.=2"
[a "3" aa [a "1"] b [c ["1" "2"]]]
]
]
url-decode: use [deplus sp decrlf][
deplus: func [text][
parse/all text [
some [to sp text: (text: change text #" ") :text] to end
]
head text
]
decrlf: func [text][
parse/all text [
some [to crlf text: (text: change/part text #"^/" 2) :text] to end
]
head text
]
func [text [any-string! none!] /wiki][
sp: either wiki [#"_"][#"+"]
decrlf dehex deplus form any [text ""]
]
]
load-webform: use [result path string pair as-path multi? pairs?][
result: copy []
as-path: func [name [string!]][to-path to-block replace/all name #"." #" "]
path: use [aa an wd][
aa: charset [#"A" - #"Z" #"a" - #"z"]
an: union aa charset ["-_" #"0" - #"9"]
wd: [aa 0 40 an] ; one alpha, any alpha/digit/dash/underscore
[wd 0 6 [#"." wd]]
]
string: use [ch hx][
ch: charset ["!'*,-._~" #"0" - #"9" #"A" - #"Z" #"a" - #"z"]
hx: charset [#"0" - #"9" #"A" - #"F" #"a" - #"f"]
[any [ch | #"+" | #"%" 2 hx]] ; any [unreserved | percent-encoded]
]
multi?: func [value [none! string! block!]][
all [
block? value
parse value [some string!]
]
]
pairs?: func [value [none! string! block!]][
all [
block? value
parse value [some [word! skip]]
]
]
pair: use [name value tree is-block?][
[
copy name path copy is-block? opt #"."
#"=" copy value string [#"&" | end]
(
tree: :result
name: as-path name
value: url-decode value
until [
tree: any [
find/tail tree name/1
insert tail tree name/1
]
name: next name
either tail? name [
either is-block? [
unless multi? tree/1 [
change/only tree copy []
]
append tree/1 value
][
change tree value
]
true
][
either pairs? tree/1 [
tree: tree/1
][
change/only tree tree: copy []
]
false
]
]
)
]
]
func [
[catch] "Loads Data from a URL-Encoded Web Form string"
webform [string! none!]
][
webform: any [webform ""]
result: copy []
either parse/all webform [opt #"&" any pair][result][
make error! "Not a URL Encoded Web Form"
]
]
]
url-encode: use [ch sp encode][
ch: charset ["!'*,-.~" #"0" - #"9" #"A" - #"Z" #"a" - #"z"]
encode: func [text][insert next text enbase/base form text/1 16 change text "%"]
func [text [any-string!] /wiki][
sp: either wiki [#"_"][#"+"]
parse/all copy text [
copy text some [
text: some ch | #" " (change text sp)
| #"_" (all [wiki encode text]) | skip (encode text)
] | end (text: copy "")
]
text
]
]
to-webform: use [
webform form-key emit in-block?
here path reference value block array object
][
path: []
in-block?: false
form-key: has [key][
key: remove head foreach name path [insert "" reduce ["." name]]
if in-block? [append key "."]
key
]
emit: func [data][
repend webform ["&" form-key "=" url-encode data]
]
reference: [
here: get-word! (change/only here attempt [get/any here/1]) :here
]
value: [
here: number! (emit form here/1)
| [logic! | 'true | 'false] (emit form here/1)
| [none! | 'none]
| date! (replace form date "/" "T")
| [any-string! | tuple! | money! | time! | pair!] (emit form here/1)
| [word! | set-word! | lit-word!] (emit form here/1)
| block
| some reference value
| skip ; (emit mold type? here/1)
]
array: [
(in-block?: true)
any value end
(in-block?: false)
]
object: [
here: any [[word! | set-word!] skip] end :here ; check pair format...
any [
here: [word! | set-word!] (insert path to word! here/1)
value (remove path)
] end
]
block: [
here: [
any-block! (change/only here copy here/1)
| object! (change/only here body-of here/1)
] :here into [object | array]
]
func [
[catch] "Serializes block data as URL-Encoded Web Form string"
data [block! object!] /prefix
][
clear path
webform: copy ""
data: either object? data [body-of data][copy data]
throw-on-error [assert [parse copy data object]]
either all [prefix not tail? next webform][back change webform "?"][remove webform]
]
]