Advertisement
StavenCross

Untitled

Nov 5th, 2020 (edited)
3,009
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
  2. ; #Warn  ; Enable warnings to assist with detecting common errors.
  3. SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
  4. SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
  5.  
  6. inputFile := "inv_config_data.csv"
  7.  
  8.  
  9.     FileCreateDir, ChromeProfile
  10.     global ChromeInst := new Chrome("ChromeProfile", "https://dna.dealer.com/views/clients/client-dashboard/client-dashboard?accountId=lhm")
  11.     sleep, 2000
  12.     global PageInst := ChromeInst.GetPageByURL("https://dna.dealer.com/views/clients/client-dashboard/client-dashboard?accountId=lhm")
  13.     PageInst.WaitForLoad()
  14.     sleep, 13000
  15.     ;mouseMove, 2490, 470, 0
  16.     Click, 2490, 470
  17.     sleep,  5000
  18.     Click, 2367, 938
  19.     sleep, 1000
  20. changeObject :=  {} ;init obj
  21. loop,  read, %A_ScriptDir%\inv_config_data.csv
  22. {
  23.     bodyStyleFix := StrReplace(A_LoopReadLine, "Van,Minivan,Van/Minivan", "Van|Minivan|Van/Minivan") ;Just in case we have commas here we have to swap them out and then back in later
  24.     ChangeArray := StrSplit(bodyStyleFix, ",")
  25.     changeObject.push({configName:changeArray[1], exclusionAddition:changeArray[2], bodyStyleUpdate:changeArray[3]})     ;Lets go ahead and chop up the file and push it into an obj for later use reference it like this: msgbox,  % changeObject[1].configName
  26. }
  27.  
  28. loop % changeObject.maxIndex() ;now loop through the obj
  29. {
  30.     if(changeObject[A_Index].ConfigName) {
  31.         Click, 572, 190
  32.         Send, % changeObject[A_Index].ConfigName
  33.         sleep, 1000
  34.         Send, {ENTER}
  35.         sleep, 4000
  36.         if(changeObject[A_Index].exclusionAddition) {
  37.             Click, 1400, 330
  38.             Send, {HOME}
  39.             Send, % changeObject[A_Index].exclusionAddition . ","
  40.             sleep, 1000
  41.         }
  42.         if(changeObject[A_Index].bodyStyleUpdate) {
  43.             Click, 1400, 995
  44.             changeObject[A_Index].bodyStyleUpdate := StrReplace(changeObject[A_Index].bodyStyleUpdate, "|", ",")
  45.             changeObject[A_Index].bodyStyleUpdate := StrReplace(changeObject[A_Index].bodyStyleUpdate, """","" )
  46.             send, ^a
  47.             send, % changeObject[A_Index].bodyStyleUpdate
  48.             sleep, 300
  49.         }
  50.         Click, 2379, 1362
  51.         sleep, 6000
  52.         click, 32, 133
  53.         sleep, 6000
  54.         continue
  55.     } else {
  56.         msgbox,  ConfigName is empty.moving to next line
  57.         continue
  58.     }
  59. }
  60. msgbox,  Complete!
  61.  
  62.  
  63.  
  64. ESCAPE::
  65. ExitApp
  66.  
  67.  
  68.  
  69.  
  70. /*************************CHROME.AHK*****************************************************/
  71. ;Allows you to control chrome nativley with AHK.
  72.  
  73. ; Chrome.ahk v1.2
  74. ; Copyright GeekDude 2018
  75. ; https://github.com/G33kDude/Chrome.ahk
  76.  
  77. class Chrome
  78. {
  79.     static DebugPort := 9222
  80.    
  81.     /*
  82.         Escape a string in a manner suitable for command line parameters
  83.     */
  84.     CliEscape(Param)
  85.     {
  86.         return """" RegExReplace(Param, "(\\*)""", "$1$1\""") """"
  87.     }
  88.    
  89.     /*
  90.         Finds instances of chrome in debug mode and the ports they're running
  91.         on. If no instances are found, returns a false value. If one or more
  92.         instances are found, returns an associative array where the keys are
  93.         the ports, and the values are the full command line texts used to start
  94.         the processes.
  95.        
  96.         One example of how this may be used would be to open chrome on a
  97.         different port if an instance of chrome is already open on the port
  98.         you wanted to used.
  99.        
  100.         ```
  101.         ; If the wanted port is taken, use the largest taken port plus one
  102.         DebugPort := 9222
  103.         if (Chromes := Chrome.FindInstances()).HasKey(DebugPort)
  104.             DebugPort := Chromes.MaxIndex() + 1
  105.         ChromeInst := new Chrome(ProfilePath,,,, DebugPort)
  106.         ```
  107.        
  108.         Another use would be to scan for running instances and attach to one
  109.         instead of starting a new instance.
  110.        
  111.         ```
  112.         if (Chromes := Chrome.FindInstances())
  113.             ChromeInst := {"base": Chrome, "DebugPort": Chromes.MinIndex()}
  114.         else
  115.             ChromeInst := new Chrome(ProfilePath)
  116.         ```
  117.     */
  118.     FindInstances()
  119.     {
  120.         static Needle := "--remote-debugging-port=(\d+)"
  121.         Out := {}
  122.         for Item in ComObjGet("winmgmts:")
  123.             .ExecQuery("SELECT CommandLine FROM Win32_Process"
  124.             . " WHERE Name = 'chrome.exe'")
  125.             if RegExMatch(Item.CommandLine, Needle, Match)
  126.                 Out[Match1] := Item.CommandLine
  127.         return Out.MaxIndex() ? Out : False
  128.     }
  129.    
  130.     /*
  131.         ProfilePath - Path to the user profile directory to use. Will use the standard if left blank.
  132.         URLs        - The page or array of pages for Chrome to load when it opens
  133.         Flags       - Additional flags for chrome when launching
  134.         ChromePath  - Path to chrome.exe, will detect from start menu when left blank
  135.         DebugPort   - What port should Chrome's remote debugging server run on
  136.     */
  137.     __New(ProfilePath:="", URLs:="about:blank", Flags:="", ChromePath:="", DebugPort:="")
  138.     {
  139.         ; Verify ProfilePath
  140.         if (ProfilePath != "" && !InStr(FileExist(ProfilePath), "D"))
  141.             throw Exception("The given ProfilePath does not exist")
  142.         this.ProfilePath := ProfilePath
  143.        
  144.         ; Verify ChromePath
  145.         if (ChromePath == "")
  146.             FileGetShortcut, %A_StartMenuCommon%\Programs\Google Chrome.lnk, ChromePath
  147.         if (ChromePath == "")
  148.             RegRead, ChromePath, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Pahs\chrome.exe
  149.         if !FileExist(ChromePath)
  150.             throw Exception("Chrome could not be found")
  151.         this.ChromePath := ChromePath
  152.        
  153.         ; Verify DebugPort
  154.         if (DebugPort != "")
  155.         {
  156.             if DebugPort is not integer
  157.                 throw Exception("DebugPort must be a positive integer")
  158.             else if (DebugPort <= 0)
  159.                 throw Exception("DebugPort must be a positive integer")
  160.             this.DebugPort := DebugPort
  161.         }
  162.        
  163.         ; Escape the URL(s)
  164.         for Index, URL in IsObject(URLs) ? URLs : [URLs]
  165.             URLString .= " " this.CliEscape(URL)
  166.        
  167.         Run, % this.CliEscape(ChromePath)
  168.         . " --remote-debugging-port=" this.DebugPort
  169.         . (ProfilePath ? " --user-data-dir=" this.CliEscape(ProfilePath) : "")
  170.         . (Flags ? " " Flags : "")
  171.         . URLString
  172.         ,,, OutputVarPID
  173.         this.PID := OutputVarPID
  174.     }
  175.    
  176.     /*
  177.         End Chrome by terminating the process.
  178.     */
  179.     Kill()
  180.     {
  181.         Process, Close, % this.PID
  182.     }
  183.    
  184.     /*
  185.         Queries chrome for a list of pages that expose a debug interface.
  186.         In addition to standard tabs, these include pages such as extension
  187.         configuration pages.
  188.     */
  189.     GetPageList()
  190.     {
  191.         http := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  192.         http.open("GET", "http://127.0.0.1:" this.DebugPort "/json")
  193.         http.send()
  194.         return this.Jxon_Load(http.responseText)
  195.     }
  196.    
  197.     /*
  198.         Returns a connection to the debug interface of a page that matches the
  199.         provided criteria. When multiple pages match the criteria, they appear
  200.         ordered by how recently the pages were opened.
  201.        
  202.         Key        - The key from the page list to search for, such as "url" or "title"
  203.         Value      - The value to search for in the provided key
  204.         MatchMode  - What kind of search to use, such as "exact", "contains", "startswith", or "regex"
  205.         Index      - If multiple pages match the given criteria, which one of them to return
  206.         fnCallback - A function to be called whenever message is received from the page
  207.     */
  208.     GetPageBy(Key, Value, MatchMode:="exact", Index:=1, fnCallback:="")
  209.     {
  210.         Count := 0
  211.         for n, PageData in this.GetPageList()
  212.         {
  213.             if (((MatchMode = "exact" && PageData[Key] = Value) ; Case insensitive
  214.                 || (MatchMode = "contains" && InStr(PageData[Key], Value))
  215.                 || (MatchMode = "startswith" && InStr(PageData[Key], Value) == 1)
  216.                 || (MatchMode = "regex" && PageData[Key] ~= Value))
  217.                 && ++Count == Index)
  218.                 return new this.Page(PageData.webSocketDebuggerUrl, fnCallback)
  219.         }
  220.     }
  221.    
  222.     /*
  223.         Shorthand for GetPageBy("url", Value, "startswith")
  224.     */
  225.     GetPageByURL(Value, MatchMode:="startswith", Index:=1, fnCallback:="")
  226.     {
  227.         return this.GetPageBy("url", Value, MatchMode, Index, fnCallback)
  228.     }
  229.    
  230.     /*
  231.         Shorthand for GetPageBy("title", Value, "startswith")
  232.     */
  233.     GetPageByTitle(Value, MatchMode:="startswith", Index:=1, fnCallback:="")
  234.     {
  235.         return this.GetPageBy("title", Value, MatchMode, Index, fnCallback)
  236.     }
  237.    
  238.     /*
  239.         Shorthand for GetPageBy("type", Type, "exact")
  240.        
  241.         The default type to search for is "page", which is the visible area of
  242.         a normal Chrome tab.
  243.     */
  244.     GetPage(Index:=1, Type:="page", fnCallback:="")
  245.     {
  246.         return this.GetPageBy("type", Type, "exact", Index, fnCallback)
  247.     }
  248.    
  249.     /*
  250.         Connects to the debug interface of a page given its WebSocket URL.
  251.     */
  252.     class Page
  253.     {
  254.         Connected := False
  255.         ID := 0
  256.         Responses := []
  257.        
  258.         /*
  259.             wsurl      - The desired page's WebSocket URL
  260.             fnCallback - A function to be called whenever message is received
  261.         */
  262.         __New(wsurl, fnCallback:="")
  263.         {
  264.             this.fnCallback := fnCallback
  265.             this.BoundKeepAlive := this.Call.Bind(this, "Browser.getVersion",, False)
  266.            
  267.             ; TODO: Throw exception on invalid objects
  268.             if IsObject(wsurl)
  269.                 wsurl := wsurl.webSocketDebuggerUrl
  270.            
  271.             wsurl := StrReplace(wsurl, "localhost", "127.0.0.1")
  272.             this.ws := {"base": this.WebSocket, "_Event": this.Event, "Parent": this}
  273.             this.ws.__New(wsurl)
  274.            
  275.             while !this.Connected
  276.                 Sleep, 50
  277.         }
  278.        
  279.         /*
  280.             Calls the specified endpoint and provides it with the given
  281.             parameters.
  282.            
  283.             DomainAndMethod - The endpoint domain and method name for the
  284.             endpoint you would like to call. For example:
  285.             PageInst.Call("Browser.close")
  286.             PageInst.Call("Schema.getDomains")
  287.            
  288.             Params - An associative array of parameters to be provided to the
  289.             endpoint. For example:
  290.             PageInst.Call("Page.printToPDF", {"scale": 0.5 ; Numeric Value
  291.             , "landscape": Chrome.Jxon_True() ; Boolean Value
  292.             , "pageRanges: "1-5, 8, 11-13"}) ; String value
  293.             PageInst.Call("Page.navigate", {"url": "https://autohotkey.com/"})
  294.            
  295.             WaitForResponse - Whether to block until a response is received from
  296.             Chrome, which is necessary to receive a return value, or whether
  297.             to continue on with the script without waiting for a response.
  298.         */
  299.         Call(DomainAndMethod, Params:="", WaitForResponse:=True)
  300.         {
  301.            
  302.             if !this.Connected
  303.                 throw Exception("Not connected to tab")
  304.            
  305.             ; Use a temporary variable for ID in case more calls are made
  306.             ; before we receive a response.
  307.             ID := this.ID += 1
  308.             this.ws.Send(Chrome.Jxon_Dump({"id": ID
  309.             , "params": Params ? Params : {}
  310.             , "method": DomainAndMethod}))
  311.            
  312.             if !WaitForResponse
  313.                 return
  314.            
  315.             ; Wait for the response
  316.             this.responses[ID] := False
  317.             loopCounter = 0
  318.             while (!this.responses[ID]) {
  319.                 Sleep, 50
  320.                 loopCounter ++
  321.                
  322.                 if(loopCounter >50) {
  323.                     break
  324.                     msgbox, % "Eclipse did not recieve a response fast enough. Last Executed Method: " . DomainAndMethod .  " | Params: " . Params
  325.                 }
  326.             }
  327.            
  328.            
  329.             ; Get the response, check if it's an error
  330.             response := this.responses.Delete(ID)
  331.             if (response.error)
  332.                 throw Exception("Chrome indicated error in response",, Chrome.Jxon_Dump(response.error))
  333.            
  334.             ;printArray(response,1)
  335.             return response.result
  336.         }
  337.        
  338.         /*
  339.             Run some JavaScript on the page. For example:
  340.            
  341.             PageInst.Evaluate("alert(""I can't believe it's not IE!"");")
  342.             PageInst.Evaluate("document.getElementsByTagName('button')[0].click();")
  343.         */
  344.         Evaluate(JS)
  345.         {
  346.             response := this.Call("Runtime.evaluate",
  347.             ( LTrim Join
  348.             {
  349.                 "expression": JS,
  350.                 "objectGroup": "console",
  351.                 "includeCommandLineAPI": Chrome.Jxon_True(),
  352.                 "silent": Chrome.Jxon_False(),
  353.                 "returnByValue": Chrome.Jxon_False(),
  354.                 "userGesture": Chrome.Jxon_True(),
  355.                 "awaitPromise": Chrome.Jxon_True()
  356.             }
  357.             ))
  358.            
  359.             if (response.exceptionDetails)
  360.                 throw Exception(response.result.description,, Chrome.Jxon_Dump(response.exceptionDetails))
  361.            
  362.            
  363.             return response.result
  364.         }
  365.        
  366.         /*
  367.             Waits for the page's readyState to match the DesiredState.
  368.            
  369.             DesiredState - The state to wait for the page's ReadyState to match
  370.             Interval     - How often it should check whether the state matches
  371.         */
  372.         WaitForLoad(DesiredState:="complete", Interval:=100)
  373.         {
  374.             while this.Evaluate("document.readyState").value != DesiredState
  375.                 Sleep, Interval
  376.         }
  377.        
  378.         /*
  379.             Internal function triggered when the script receives a message on
  380.             the WebSocket connected to the page.
  381.         */
  382.         Event(EventName, Event)
  383.         {
  384.             ; If it was called from the WebSocket adjust the class context
  385.             if this.Parent
  386.                 this := this.Parent
  387.            
  388.             ; TODO: Handle Error events
  389.             if (EventName == "Open")
  390.             {
  391.                 this.Connected := True
  392.                 BoundKeepAlive := this.BoundKeepAlive
  393.                 SetTimer, %BoundKeepAlive%, 7000
  394.             }
  395.             else if (EventName == "Message")
  396.             {
  397.                 data := Chrome.Jxon_Load(Event.data)
  398.                
  399.                 ; Run the callback routine
  400.                 fnCallback := this.fnCallback
  401.                 if (newData := %fnCallback%(data))
  402.                     data := newData
  403.                
  404.                 if this.responses.HasKey(data.ID)
  405.                     this.responses[data.ID] := data
  406.             }
  407.             else if (EventName == "Close")
  408.             {
  409.                 this.Disconnect()
  410.             }
  411.             else if (EventName == "Error")
  412.             {
  413.                 throw Exception("Websocket Error!")
  414.             }
  415.         }
  416.        
  417.         /*
  418.             Disconnect from the page's debug interface, allowing the instance
  419.             to be garbage collected.
  420.            
  421.             This method should always be called when you are finished with a
  422.             page or else your script will leak memory.
  423.         */
  424.         Disconnect()
  425.         {
  426.             if !this.Connected
  427.                 return
  428.            
  429.             this.Connected := False
  430.             this.ws.Delete("Parent")
  431.             this.ws.Disconnect()
  432.            
  433.             BoundKeepAlive := this.BoundKeepAlive
  434.             SetTimer, %BoundKeepAlive%, Delete
  435.             this.Delete("BoundKeepAlive")
  436.         }
  437.        
  438.         class WebSocket
  439.         {
  440.             __New(WS_URL)
  441.             {
  442.                 static wb
  443.                
  444.                 ; Create an IE instance
  445.                 Gui, +hWndhOld
  446.                 Gui, New, +hWndhWnd
  447.                 this.hWnd := hWnd
  448.                 Gui, Add, ActiveX, vWB, Shell.Explorer
  449.                 Gui, %hOld%: Default
  450.                
  451.                 ; Write an appropriate document
  452.                 WB.Navigate("about:<!DOCTYPE html><meta http-equiv='X-UA-Compatible'"
  453.                 . "content='IE=edge'><body></body>")
  454.                 while (WB.ReadyState < 4)
  455.                     sleep, 50
  456.                 this.document := WB.document
  457.                
  458.                 ; Add our handlers to the JavaScript namespace
  459.                 this.document.parentWindow.ahk_savews := this._SaveWS.Bind(this)
  460.                 this.document.parentWindow.ahk_event := this._Event.Bind(this)
  461.                 this.document.parentWindow.ahk_ws_url := WS_URL
  462.                
  463.                 ; Add some JavaScript to the page to open a socket
  464.                 Script := this.document.createElement("script")
  465.                 Script.text := "ws = new WebSocket(ahk_ws_url);`n"
  466.                 . "ws.onopen = function(event){ ahk_event('Open', event); };`n"
  467.                 . "ws.onclose = function(event){ ahk_event('Close', event); };`n"
  468.                 . "ws.onerror = function(event){ ahk_event('Error', event); };`n"
  469.                 . "ws.onmessage = function(event){ ahk_event('Message', event); };"
  470.                 this.document.body.appendChild(Script)
  471.             }
  472.            
  473.             ; Called by the JS in response to WS events
  474.             _Event(EventName, Event)
  475.             {
  476.                 this["On" EventName](Event)
  477.             }
  478.            
  479.             ; Sends data through the WebSocket
  480.             Send(Data)
  481.             {
  482.                 this.document.parentWindow.ws.send(Data)
  483.             }
  484.            
  485.             ; Closes the WebSocket connection
  486.             Close(Code:=1000, Reason:="")
  487.             {
  488.                 this.document.parentWindow.ws.close(Code, Reason)
  489.             }
  490.            
  491.             ; Closes and deletes the WebSocket, removing
  492.             ; references so the class can be garbage collected
  493.             Disconnect()
  494.             {
  495.                 if this.hWnd
  496.                 {
  497.                     this.Close()
  498.                     Gui, % this.hWnd ": Destroy"
  499.                     this.hWnd := False
  500.                 }
  501.             }
  502.         }
  503.     }
  504.    
  505.     Jxon_Load(ByRef src, args*)
  506.     {
  507.         static q := Chr(34)
  508.        
  509.         key := "", is_key := false
  510.         stack := [ tree := [] ]
  511.         is_arr := { (tree): 1 }
  512.         next := q . "{[01234567890-tfn"
  513.         pos := 0
  514.         while ( (ch := SubStr(src, ++pos, 1)) != "" )
  515.         {
  516.             if InStr(" `t`n`r", ch)
  517.                 continue
  518.             if !InStr(next, ch, true)
  519.             {
  520.                 ln := ObjLength(StrSplit(SubStr(src, 1, pos), "`n"))
  521.                 col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1))
  522.                
  523.                 msg := Format("{}: line {} col {} (char {})"
  524.                 ,   (next == "")      ? ["Extra data", ch := SubStr(src, pos)][1]
  525.                 : (next == "'")     ? "Unterminated string starting at"
  526.                 : (next == "\")     ? "Invalid \escape"
  527.                 : (next == ":")     ? "Expecting ':' delimiter"
  528.                 : (next == q)       ? "Expecting object key enclosed in double quotes"
  529.                 : (next == q . "}") ? "Expecting object key enclosed in double quotes or object closing '}'"
  530.                 : (next == ",}")    ? "Expecting ',' delimiter or object closing '}'"
  531.                 : (next == ",]")    ? "Expecting ',' delimiter or array closing ']'"
  532.                 : [ "Expecting JSON value(string, number, [true, false, null], object or array)"
  533.                 , ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1]
  534.                 , ln, col, pos)
  535.                
  536.                 throw Exception(msg, -1, ch)
  537.             }
  538.            
  539.             is_array := is_arr[obj := stack[1]]
  540.            
  541.             if i := InStr("{[", ch)
  542.             {
  543.                 val := (proto := args[i]) ? new proto : {}
  544.                 is_array? ObjPush(obj, val) : obj[key] := val
  545.                 ObjInsertAt(stack, 1, val)
  546.                
  547.                 is_arr[val] := !(is_key := ch == "{")
  548.                 next := q . (is_key ? "}" : "{[]0123456789-tfn")
  549.             }
  550.            
  551.             else if InStr("}]", ch)
  552.             {
  553.                 ObjRemoveAt(stack, 1)
  554.                 next := stack[1]==tree ? "" : is_arr[stack[1]] ? ",]" : ",}"
  555.             }
  556.            
  557.             else if InStr(",:", ch)
  558.             {
  559.                 is_key := (!is_array && ch == ",")
  560.                 next := is_key ? q : q . "{[0123456789-tfn"
  561.             }
  562.            
  563.             else ; string | number | true | false | null
  564.             {
  565.                 if (ch == q) ; string
  566.                 {
  567.                     i := pos
  568.                     while i := InStr(src, q,, i+1)
  569.                     {
  570.                         val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C")
  571.                         static end := A_AhkVersion<"2" ? 0 : -1
  572.                         if (SubStr(val, end) != "\")
  573.                             break
  574.                     }
  575.                     if !i ? (pos--, next := "'") : 0
  576.                         continue
  577.                    
  578.                     pos := i ; update pos
  579.                    
  580.                     val := StrReplace(val,    "\/",  "/")
  581.                     , val := StrReplace(val, "\" . q,    q)
  582.                     , val := StrReplace(val,    "\b", "`b")
  583.                     , val := StrReplace(val,    "\f", "`f")
  584.                     , val := StrReplace(val,    "\n", "`n")
  585.                     , val := StrReplace(val,    "\r", "`r")
  586.                     , val := StrReplace(val,    "\t", "`t")
  587.                    
  588.                     i := 0
  589.                     while i := InStr(val, "\",, i+1)
  590.                     {
  591.                         if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0
  592.                             continue 2
  593.                        
  594.                         ; \uXXXX - JSON unicode escape sequence
  595.                         xxxx := Abs("0x" . SubStr(val, i+2, 4))
  596.                         if (A_IsUnicode || xxxx < 0x100)
  597.                             val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6)
  598.                     }
  599.                    
  600.                     if is_key
  601.                     {
  602.                         key := val, next := ":"
  603.                         continue
  604.                     }
  605.                 }
  606.                
  607.                 else ; number | true | false | null
  608.                 {
  609.                     val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos)
  610.                    
  611.                     ; For numerical values, numerify integers and keep floats as is.
  612.                     ; I'm not yet sure if I should numerify floats in v2.0-a ...
  613.                     static number := "number", integer := "integer"
  614.                     if val is %number%
  615.                     {
  616.                         if val is %integer%
  617.                             val += 0
  618.                     }
  619.                     ; in v1.1, true,false,A_PtrSize,A_IsUnicode,A_Index,A_EventInfo,
  620.                     ; SOMETIMES return strings due to certain optimizations. Since it
  621.                     ; is just 'SOMETIMES', numerify to be consistent w/ v2.0-a
  622.                     else if (val == "true" || val == "false")
  623.                         val := %value% + 0
  624.                     ; AHK_H has built-in null, can't do 'val := %value%' where value == "null"
  625.                     ; as it would raise an exception in AHK_H(overriding built-in var)
  626.                     else if (val == "null")
  627.                         val := ""
  628.                     ; any other values are invalid, continue to trigger error
  629.                     else if (pos--, next := "#")
  630.                         continue
  631.                    
  632.                     pos += i-1
  633.                 }
  634.                
  635.                 is_array? ObjPush(obj, val) : obj[key] := val
  636.                 next := obj==tree ? "" : is_array ? ",]" : ",}"
  637.             }
  638.         }
  639.        
  640.         return tree[1]
  641.     }
  642.    
  643.     Jxon_Dump(obj, indent:="", lvl:=1)
  644.     {
  645.         static q := Chr(34)
  646.        
  647.         if IsObject(obj)
  648.         {
  649.             static Type := Func("Type")
  650.             if Type ? (Type.Call(obj) != "Object") : (ObjGetCapacity(obj) == "")
  651.                 throw Exception("Object type not supported.", -1, Format("<Object at 0x{:p}>", &obj))
  652.            
  653.             prefix := SubStr(A_ThisFunc, 1, InStr(A_ThisFunc, ".",, 0))
  654.             fn_t := prefix "Jxon_True",  obj_t := this ? %fn_t%(this) : %fn_t%()
  655.             fn_f := prefix "Jxon_False", obj_f := this ? %fn_f%(this) : %fn_f%()
  656.            
  657.             if (&obj == &obj_t)
  658.                 return "true"
  659.             else if (&obj == &obj_f)
  660.                 return "false"
  661.            
  662.             is_array := 0
  663.             for k in obj
  664.                 is_array := k == A_Index
  665.             until !is_array
  666.            
  667.             static integer := "integer"
  668.             if indent is %integer%
  669.             {
  670.                 if (indent < 0)
  671.                     throw Exception("Indent parameter must be a postive integer.", -1, indent)
  672.                 spaces := indent, indent := ""
  673.                 Loop % spaces
  674.                     indent .= " "
  675.             }
  676.             indt := ""
  677.             Loop, % indent ? lvl : 0
  678.                 indt .= indent
  679.            
  680.             this_fn := this ? Func(A_ThisFunc).Bind(this) : A_ThisFunc
  681.             lvl += 1, out := "" ; Make #Warn happy
  682.             for k, v in obj
  683.             {
  684.                 if IsObject(k) || (k == "")
  685.                     throw Exception("Invalid object key.", -1, k ? Format("<Object at 0x{:p}>", &obj) : "<blank>")
  686.                
  687.                 if !is_array
  688.                     out .= ( ObjGetCapacity([k], 1) ? %this_fn%(k) : q . k . q ) ;// key
  689.                 .  ( indent ? ": " : ":" ) ; token + padding
  690.                 out .= %this_fn%(v, indent, lvl) ; value
  691.                 .  ( indent ? ",`n" . indt : "," ) ; token + indent
  692.             }
  693.            
  694.             if (out != "")
  695.             {
  696.                 out := Trim(out, ",`n" . indent)
  697.                 if (indent != "")
  698.                     out := "`n" . indt . out . "`n" . SubStr(indt, StrLen(indent)+1)
  699.             }
  700.            
  701.             return is_array ? "[" . out . "]" : "{" . out . "}"
  702.         }
  703.        
  704.         ; Number
  705.         else if (ObjGetCapacity([obj], 1) == "")
  706.             return obj
  707.        
  708.         ; String (null -> not supported by AHK)
  709.         if (obj != "")
  710.         {
  711.             obj := StrReplace(obj,  "\",    "\\")
  712.             , obj := StrReplace(obj,  "/",    "\/")
  713.             , obj := StrReplace(obj,    q, "\" . q)
  714.             , obj := StrReplace(obj, "`b",    "\b")
  715.             , obj := StrReplace(obj, "`f",    "\f")
  716.             , obj := StrReplace(obj, "`n",    "\n")
  717.             , obj := StrReplace(obj, "`r",    "\r")
  718.             , obj := StrReplace(obj, "`t",    "\t")
  719.            
  720.             static needle := (A_AhkVersion<"2" ? "O)" : "") . "[^\x20-\x7e]"
  721.             while RegExMatch(obj, needle, m)
  722.                 obj := StrReplace(obj, m[0], Format("\u{:04X}", Ord(m[0])))
  723.         }
  724.        
  725.         return q . obj . q
  726.     }
  727.    
  728.     Jxon_True()
  729.     {
  730.         static obj := {}
  731.         return obj
  732.     }
  733.    
  734.     Jxon_False()
  735.     {
  736.         static obj := {}
  737.         return obj
  738.     }
  739. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement