mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			202 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Forth
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Forth
		
	
	
	
	
	
namespace Nessos.FsPickler.Json
 | 
						|
 | 
						|
    open System
 | 
						|
    open System.Collections.Generic
 | 
						|
    open System.Globalization
 | 
						|
    open System.IO
 | 
						|
    open System.Numerics
 | 
						|
    open System.Text
 | 
						|
 | 
						|
    open Newtonsoft.Json
 | 
						|
 | 
						|
    open Nessos.FsPickler
 | 
						|
 | 
						|
    /// <summary>
 | 
						|
    ///     Json format deserializer
 | 
						|
    /// </summary>
 | 
						|
    type internal JsonPickleReader (jsonReader : JsonReader, omitHeader, isTopLevelSequence, leaveOpen) =
 | 
						|
 | 
						|
        do
 | 
						|
            jsonReader.CloseInput <- not leaveOpen
 | 
						|
            jsonReader.SupportMultipleContent <- isTopLevelSequence
 | 
						|
 | 
						|
        let isBsonReader = match jsonReader with :? Bson.BsonReader -> true | _ -> false
 | 
						|
 | 
						|
        let mutable depth = 0
 | 
						|
        let arrayStack = new Stack<int> ()
 | 
						|
        do arrayStack.Push Int32.MinValue
 | 
						|
 | 
						|
        // do not write tag if omitting header or array element
 | 
						|
        let omitTag () = (omitHeader && depth = 0) || arrayStack.Peek() = depth - 1
 | 
						|
 | 
						|
        interface IPickleFormatReader with
 | 
						|
            
 | 
						|
            member __.BeginReadRoot (tag : string) =
 | 
						|
                do jsonReader.Read() |> ignore
 | 
						|
                    
 | 
						|
                if omitHeader then () else
 | 
						|
 | 
						|
                if jsonReader.TokenType <> JsonToken.StartObject then raise <| new FormatException("invalid json root object.")
 | 
						|
                else
 | 
						|
                    do jsonReader.MoveNext()
 | 
						|
                    let version = jsonReader.ReadPrimitiveAs<string> false "FsPickler"
 | 
						|
                    if version <> jsonFormatVersion then
 | 
						|
                        let v = Version(version)
 | 
						|
                        raise <| new FormatException(sprintf "Invalid FsPickler format version %O." version)
 | 
						|
 | 
						|
                    let sTag = jsonReader.ReadPrimitiveAs<string> false "type"
 | 
						|
                    if tag <> sTag then
 | 
						|
                        raise <| new InvalidPickleTypeException(tag, sTag)
 | 
						|
 | 
						|
            member __.EndReadRoot () = 
 | 
						|
                if not omitHeader then jsonReader.Read() |> ignore
 | 
						|
 | 
						|
            member __.BeginReadObject (tag : string) =
 | 
						|
                
 | 
						|
                if not <| omitTag () then
 | 
						|
                    jsonReader.ReadProperty tag
 | 
						|
                    jsonReader.MoveNext ()
 | 
						|
 | 
						|
                if isTopLevelSequence && depth = 0 then
 | 
						|
                    arrayStack.Push depth
 | 
						|
                    depth <- depth + 1
 | 
						|
                    ObjectFlags.IsSequenceHeader
 | 
						|
 | 
						|
                else
 | 
						|
                    match jsonReader.TokenType with
 | 
						|
                    | JsonToken.Null -> ObjectFlags.IsNull
 | 
						|
                    | JsonToken.StartArray ->
 | 
						|
                        jsonReader.MoveNext()
 | 
						|
                        arrayStack.Push depth
 | 
						|
                        depth <- depth + 1
 | 
						|
                        ObjectFlags.IsSequenceHeader
 | 
						|
 | 
						|
                    | JsonToken.StartObject ->
 | 
						|
                        do jsonReader.MoveNext()
 | 
						|
                        depth <- depth + 1
 | 
						|
 | 
						|
                        if jsonReader.ValueAs<string> () = "_flags" then
 | 
						|
                            jsonReader.MoveNext()
 | 
						|
                            let csvFlags = jsonReader.ValueAs<string>()
 | 
						|
                            jsonReader.MoveNext()
 | 
						|
                            parseFlagCsv csvFlags
 | 
						|
                        else
 | 
						|
                            ObjectFlags.None
 | 
						|
 | 
						|
                    | token -> raise <| new FormatException(sprintf "expected start of Json object but was '%O'." token)
 | 
						|
 | 
						|
 | 
						|
            member __.EndReadObject () =
 | 
						|
                if isTopLevelSequence && depth = 1 then
 | 
						|
                    arrayStack.Pop () |> ignore
 | 
						|
                    depth <- depth - 1
 | 
						|
                    jsonReader.Read() |> ignore
 | 
						|
                else
 | 
						|
                    match jsonReader.TokenType with
 | 
						|
                    | JsonToken.Null -> ()
 | 
						|
                    | JsonToken.EndObject -> depth <- depth - 1
 | 
						|
                    | JsonToken.EndArray ->
 | 
						|
                        arrayStack.Pop() |> ignore
 | 
						|
                        depth <- depth - 1
 | 
						|
 | 
						|
                    | token -> raise <| new FormatException(sprintf "expected end of Json object but was '%O'." token)
 | 
						|
 | 
						|
                    if omitHeader && depth = 0 then ()
 | 
						|
                    else jsonReader.Read() |> ignore
 | 
						|
 | 
						|
            member __.SerializeUnionCaseNames = true
 | 
						|
 | 
						|
            member __.PreferLengthPrefixInSequences = false
 | 
						|
            member __.ReadNextSequenceElement () = 
 | 
						|
                if isTopLevelSequence && depth = 1 then
 | 
						|
                    jsonReader.TokenType <> JsonToken.None
 | 
						|
                else
 | 
						|
                    jsonReader.TokenType <> JsonToken.EndArray
 | 
						|
 | 
						|
            member __.ReadCachedObjectId () = jsonReader.ReadPrimitiveAs<int64> false "id"
 | 
						|
 | 
						|
            member __.ReadBoolean tag = jsonReader.ReadPrimitiveAs<bool> (omitTag ()) tag
 | 
						|
            member __.ReadByte tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag |> byte
 | 
						|
            member __.ReadSByte tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag |> sbyte
 | 
						|
 | 
						|
            member __.ReadInt16 tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag |> int16
 | 
						|
            member __.ReadInt32 tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag |> int
 | 
						|
            member __.ReadInt64 tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag
 | 
						|
 | 
						|
            member __.ReadUInt16 tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag |> uint16
 | 
						|
            member __.ReadUInt32 tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag |> uint32
 | 
						|
            member __.ReadUInt64 tag = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag |> uint64
 | 
						|
 | 
						|
            member __.ReadSingle tag =
 | 
						|
                if not <| omitTag () then
 | 
						|
                    jsonReader.ReadProperty tag
 | 
						|
                    jsonReader.MoveNext()
 | 
						|
 | 
						|
                let value =
 | 
						|
                    match jsonReader.TokenType with
 | 
						|
                    | JsonToken.Float -> jsonReader.ValueAs<double> () |> single
 | 
						|
                    | JsonToken.String -> Single.Parse(jsonReader.ValueAs<string>(), CultureInfo.InvariantCulture)
 | 
						|
                    | _ -> raise <| new FormatException("not a float.")
 | 
						|
 | 
						|
                jsonReader.Read() |> ignore
 | 
						|
                value
 | 
						|
                
 | 
						|
            member __.ReadDouble tag =
 | 
						|
                if not <| omitTag () then
 | 
						|
                    jsonReader.ReadProperty tag
 | 
						|
                    jsonReader.MoveNext()
 | 
						|
 | 
						|
                let value =
 | 
						|
                    match jsonReader.TokenType with
 | 
						|
                    | JsonToken.Float -> jsonReader.ValueAs<double> ()
 | 
						|
                    | JsonToken.String -> Double.Parse(jsonReader.ValueAs<string>(), CultureInfo.InvariantCulture)
 | 
						|
                    | _ -> raise <| new FormatException("not a float.")
 | 
						|
 | 
						|
                jsonReader.Read() |> ignore
 | 
						|
                value
 | 
						|
 | 
						|
            member __.ReadChar tag = let value = jsonReader.ReadPrimitiveAs<string> (omitTag ()) tag in value.[0]
 | 
						|
            member __.ReadString tag = jsonReader.ReadPrimitiveAs<string> (omitTag ()) tag
 | 
						|
            member __.ReadBigInteger tag = jsonReader.ReadPrimitiveAs<string> (omitTag ()) tag |> BigInteger.Parse
 | 
						|
 | 
						|
            member __.ReadGuid tag = 
 | 
						|
                if isBsonReader then 
 | 
						|
                    jsonReader.ReadPrimitiveAs<Guid> (omitTag ()) tag
 | 
						|
                else
 | 
						|
                    jsonReader.ReadPrimitiveAs<string> (omitTag ()) tag |> Guid.Parse
 | 
						|
 | 
						|
            member __.ReadTimeSpan tag = jsonReader.ReadPrimitiveAs<string> (omitTag ()) tag |> TimeSpan.Parse
 | 
						|
            member __.ReadDecimal tag = jsonReader.ReadPrimitiveAs<string> (omitTag ()) tag |> decimal
 | 
						|
 | 
						|
            // BSON spec mandates the use of Unix time; 
 | 
						|
            // this has millisecond precision which results in loss of accuracy w.r.t. ticks
 | 
						|
            // since the goal of FsPickler is to offer faithful representations of .NET objects
 | 
						|
            // we choose to override the spec and serialize ticks outright.
 | 
						|
            // see also https://json.codeplex.com/discussions/212067 
 | 
						|
            member __.ReadDate tag = 
 | 
						|
                if isBsonReader then
 | 
						|
                    let ticks = jsonReader.ReadPrimitiveAs<int64> (omitTag ()) tag
 | 
						|
                    DateTime(ticks)
 | 
						|
                else
 | 
						|
                    jsonReader.ReadPrimitiveAs<DateTime> (omitTag ()) tag
 | 
						|
 | 
						|
            member __.ReadBytes tag =
 | 
						|
                if not <| omitTag () then
 | 
						|
                    jsonReader.ReadProperty tag
 | 
						|
                    jsonReader.Read() |> ignore
 | 
						|
 | 
						|
                let bytes =
 | 
						|
                    if jsonReader.TokenType = JsonToken.Null then null
 | 
						|
                    elif isBsonReader then jsonReader.ValueAs<byte []> ()
 | 
						|
                    else
 | 
						|
                        let base64 = jsonReader.ValueAs<string> ()
 | 
						|
                        Convert.FromBase64String base64
 | 
						|
 | 
						|
                jsonReader.Read() |> ignore
 | 
						|
 | 
						|
                bytes
 | 
						|
 | 
						|
            member __.IsPrimitiveArraySerializationSupported = false
 | 
						|
            member __.ReadPrimitiveArray _ _ = raise <| new NotImplementedException()
 | 
						|
 | 
						|
            member __.Dispose () = (jsonReader :> IDisposable).Dispose() |