Parses a string while reading a JSON file.
string
is now returned unescaped.Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(json_core), | intent(inout) | :: | json | |||
integer(kind=IK), | intent(in) | :: | unit | file unit number (if parsing from a file) |
||
character(kind=CK,len=*), | intent(in) | :: | str | JSON string (if parsing from a string) |
||
character(kind=CK,len=:), | intent(out), | allocatable | :: | string | the string (unescaped if necessary) |
subroutine parse_string(json, unit, str, string)
implicit none
class(json_core),intent(inout) :: json
integer(IK),intent(in) :: unit !! file unit number (if parsing from a file)
character(kind=CK,len=*),intent(in) :: str !! JSON string (if parsing from a string)
character(kind=CK,len=:),allocatable,intent(out) :: string !! the string (unescaped if necessary)
logical(LK) :: eof !! end of file flag
logical(LK) :: is_hex !! it is a hex string
logical(LK) :: escape !! for escape string parsing
character(kind=CK,len=1) :: c !! character returned by [[pop_char]]
character(kind=CK,len=4) :: hex !! hex string
integer(IK) :: i !! counter
integer(IK) :: ip !! index to put next character,
!! to speed up by reducing the number
!! of character string reallocations.
character(kind=CK,len=:),allocatable :: string_unescaped !! temp variable
character(kind=CK,len=:),allocatable :: error_message !! for string unescaping
!at least return a blank string if there is a problem:
string = repeat(space, chunk_size)
if (.not. json%exception_thrown) then
!initialize:
ip = 1
is_hex = .false.
escape = .false.
i = 0
do
!get the next character from the file:
call json%pop_char(unit, str=str, eof=eof, skip_ws=.false., popped=c)
if (eof) then
call json%throw_exception('Error in parse_string: Expecting end of string')
return
else if (c==quotation_mark .and. .not. escape) then !end of string
if (is_hex) call json%throw_exception('Error in parse_string:'//&
' incomplete hex string: \u'//trim(hex))
exit
else
!if the string is not big enough, then add another chunk:
if (ip>len(string)) string = string // repeat(space, chunk_size)
!append to string:
string(ip:ip) = c
ip = ip + 1
!hex validation:
if (is_hex) then !accumulate the four characters after '\u'
i=i+1
hex(i:i) = c
if (i==4) then
if (valid_json_hex(hex)) then
i = 0
hex = CK_''
is_hex = .false.
else
call json%throw_exception('Error in parse_string:'//&
' invalid hex string: \u'//trim(hex))
exit
end if
end if
else
!when the '\u' string is encountered, then
! start accumulating the hex string (should be the next 4 characters)
if (escape) then
escape = .false.
is_hex = (c==CK_'u') !the next four characters are the hex string
else
escape = (c==backslash)
end if
end if
end if
end do
!trim the string if necessary:
if (ip<len(string)+1) then
if (ip==1) then
string = CK_''
else
string = string(1:ip-1)
end if
end if
!string is returned unescaped:
call unescape_string(string,string_unescaped,error_message)
if (allocated(error_message)) then
call json%throw_exception(error_message)
else
string = string_unescaped
end if
!cleanup:
if (allocated(error_message)) deallocate(error_message)
if (allocated(string_unescaped)) deallocate(string_unescaped)
end if
end subroutine parse_string