(原创)Delphi的JSON库 - DJSON(1) - JSONTokener

今天开始翻译JSON-RPC。在翻译的过程中,碰到一些语言方面的问题,如:

1、Java支持垃圾回收,Delphi不支持,在此我使用Delphi中的智能指针替代。

2、Java中有Boolean、Integer、Long等类,Delphi没有,我便按照Java的方法分别创建了TBooleanObject、TIntegerObject、TLongObject等类。

3、在C语法和Pascal语法之间切换,头有点疼……

 

但我已下定决心把DJson做完!

现在用Delphi的人不多,原因有两点:

1、公司管理层的问题。

2、关于Delphi相关成熟的库太少。

 

既然第一点已经无法挽回,那就让我们在第二点上做努力吧!

 

首先贴出Java源代码:

ContractedBlock.gif ExpandedBlockStart.gif Code
  1package org.json;
  2
  3ExpandedBlockStart.gifContractedBlock.gif/**//*
  4Copyright (c) 2002 JSON.org
  5
  6Permission is hereby granted, free of charge, to any person obtaining a copy
  7of this software and associated documentation files (the "Software"), to deal
  8in the Software without restriction, including without limitation the rights
  9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10copies of the Software, and to permit persons to whom the Software is
 11furnished to do so, subject to the following conditions:
 12
 13The above copyright notice and this permission notice shall be included in all
 14copies or substantial portions of the Software.
 15
 16The Software shall be used for Good, not Evil.
 17
 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 24SOFTWARE.
 25*/

 26
 27ExpandedBlockStart.gifContractedBlock.gif/** *//**
 28 * A JSONTokener takes a source string and extracts characters and tokens from
 29 * it. It is used by the JSONObject and JSONArray constructors to parse
 30 * JSON source strings.
 31 * @author JSON.org
 32 * @version 2
 33 */

 34ExpandedBlockStart.gifContractedBlock.gifpublic class JSONTokener {
 35
 36ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
 37     * The index of the next character.
 38     */

 39    private int myIndex;
 40
 41
 42ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
 43     * The source string being tokenized.
 44     */

 45    private String mySource;
 46
 47
 48ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
 49     * Construct a JSONTokener from a string.
 50     *
 51     * @param s     A source string.
 52     */

 53ExpandedSubBlockStart.gifContractedSubBlock.gif    public JSONTokener(String s) {
 54        this.myIndex = 0;
 55        this.mySource = s;
 56    }

 57
 58
 59ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
 60     * Back up one character. This provides a sort of lookahead capability,
 61     * so that you can test for a digit or letter before attempting to parse
 62     * the next number or identifier.
 63     */

 64ExpandedSubBlockStart.gifContractedSubBlock.gif    public void back() {
 65ExpandedSubBlockStart.gifContractedSubBlock.gif        if (this.myIndex > 0{
 66            this.myIndex -= 1;
 67        }

 68    }

 69
 70
 71
 72ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
 73     * Get the hex value of a character (base16).
 74     * @param c A character between '0' and '9' or between 'A' and 'F' or
 75     * between 'a' and 'f'.
 76     * @return  An int between 0 and 15, or -1 if c was not a hex digit.
 77     */

 78ExpandedSubBlockStart.gifContractedSubBlock.gif    public static int dehexchar(char c) {
 79ExpandedSubBlockStart.gifContractedSubBlock.gif        if (c >= '0' && c <= '9'{
 80            return c - '0';
 81        }

 82ExpandedSubBlockStart.gifContractedSubBlock.gif        if (c >= 'A' && c <= 'F'{
 83            return c - ('A' - 10);
 84        }

 85ExpandedSubBlockStart.gifContractedSubBlock.gif        if (c >= 'a' && c <= 'f'{
 86            return c - ('a' - 10);
 87        }

 88        return -1;
 89    }

 90
 91
 92ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
 93     * Determine if the source string still contains characters that next()
 94     * can consume.
 95     * @return true if not yet at the end of the source.
 96     */

 97ExpandedSubBlockStart.gifContractedSubBlock.gif    public boolean more() {
 98        return this.myIndex < this.mySource.length();
 99    }

100
101
102ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
103     * Get the next character in the source string.
104     *
105     * @return The next character, or 0 if past the end of the source string.
106     */

107ExpandedSubBlockStart.gifContractedSubBlock.gif    public char next() {
108ExpandedSubBlockStart.gifContractedSubBlock.gif        if (more()) {
109            char c = this.mySource.charAt(this.myIndex);
110            this.myIndex += 1;
111            return c;
112        }

113        return 0;
114    }

115
116
117ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
118     * Consume the next character, and check that it matches a specified
119     * character.
120     * @param c The character to match.
121     * @return The character.
122     * @throws JSONException if the character does not match.
123     */

124ExpandedSubBlockStart.gifContractedSubBlock.gif    public char next(char c) throws JSONException {
125        char n = next();
126ExpandedSubBlockStart.gifContractedSubBlock.gif        if (n != c) {
127            throw syntaxError("Expected '" + c + "' and instead saw '" +
128                    n + "'");
129        }

130        return n;
131    }

132
133
134ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
135     * Get the next n characters.
136     *
137     * @param n     The number of characters to take.
138     * @return      A string of n characters.
139     * @throws JSONException
140     *   Substring bounds error if there are not
141     *   n characters remaining in the source string.
142     */

143ExpandedSubBlockStart.gifContractedSubBlock.gif     public String next(int n) throws JSONException {
144         int i = this.myIndex;
145         int j = i + n;
146ExpandedSubBlockStart.gifContractedSubBlock.gif         if (j >= this.mySource.length()) {
147            throw syntaxError("Substring bounds error");
148         }

149         this.myIndex += n;
150         return this.mySource.substring(i, j);
151     }

152
153
154ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
155     * Get the next char in the string, skipping whitespace
156     * and comments (slashslash, slashstar, and hash).
157     * @throws JSONException
158     * @return  A character, or 0 if there are no more characters.
159     */

160ExpandedSubBlockStart.gifContractedSubBlock.gif    public char nextClean() throws JSONException {
161ExpandedSubBlockStart.gifContractedSubBlock.gif        for (;;) {
162            char c = next();
163ExpandedSubBlockStart.gifContractedSubBlock.gif            if (c == '/'{
164ExpandedSubBlockStart.gifContractedSubBlock.gif                switch (next()) {
165                case '/':
166ExpandedSubBlockStart.gifContractedSubBlock.gif                    do {
167                        c = next();
168                    }
 while (c != '\n' && c != '\r' && c != 0);
169                    break;
170                case '*':
171ExpandedSubBlockStart.gifContractedSubBlock.gif                    for (;;) {
172                        c = next();
173ExpandedSubBlockStart.gifContractedSubBlock.gif                        if (c == 0{
174                            throw syntaxError("Unclosed comment");
175                        }

176ExpandedSubBlockStart.gifContractedSubBlock.gif                        if (c == '*'{
177ExpandedSubBlockStart.gifContractedSubBlock.gif                            if (next() == '/'{
178                                break;
179                            }

180                            back();
181                        }

182                    }

183                    break;
184                default:
185                    back();
186                    return '/';
187                }

188ExpandedSubBlockStart.gifContractedSubBlock.gif            }
 else if (c == '#'{
189ExpandedSubBlockStart.gifContractedSubBlock.gif                do {
190                    c = next();
191                }
 while (c != '\n' && c != '\r' && c != 0);
192ExpandedSubBlockStart.gifContractedSubBlock.gif            }
 else if (c == 0 || c > ' '{
193                return c;
194            }

195        }

196    }

197
198
199ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
200     * Return the characters up to the next close quote character.
201     * Backslash processing is done. The formal JSON format does not
202     * allow strings in single quotes, but an implementation is allowed to
203     * accept them.
204     * @param quote The quoting character, either
205     *      <code>"</code>&nbsp;<small>(double quote)</small> or
206     *      <code>'</code>&nbsp;<small>(single quote)</small>.
207     * @return      A String.
208     * @throws JSONException Unterminated string.
209     */

210ExpandedSubBlockStart.gifContractedSubBlock.gif    public String nextString(char quote) throws JSONException {
211        char c;
212        StringBuffer sb = new StringBuffer();
213ExpandedSubBlockStart.gifContractedSubBlock.gif        for (;;) {
214            c = next();
215ExpandedSubBlockStart.gifContractedSubBlock.gif            switch (c) {
216            case 0:
217            case '\n':
218            case '\r':
219                throw syntaxError("Unterminated string");
220            case '\\':
221                c = next();
222ExpandedSubBlockStart.gifContractedSubBlock.gif                switch (c) {
223                case 'b':
224                    sb.append('\b');
225                    break;
226                case 't':
227                    sb.append('\t');
228                    break;
229                case 'n':
230                    sb.append('\n');
231                    break;
232                case 'f':
233                    sb.append('\f');
234                    break;
235                case 'r':
236                    sb.append('\r');
237                    break;
238                case 'u':
239                    sb.append((char)Integer.parseInt(next(4), 16));
240                    break;
241                case 'x' :
242                    sb.append((char) Integer.parseInt(next(2), 16));
243                    break;
244                default:
245                    sb.append(c);
246                }

247                break;
248            default:
249ExpandedSubBlockStart.gifContractedSubBlock.gif                if (c == quote) {
250                    return sb.toString();
251                }

252                sb.append(c);
253            }

254        }

255    }

256
257
258ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
259     * Get the text up but not including the specified character or the
260     * end of line, whichever comes first.
261     * @param  d A delimiter character.
262     * @return   A string.
263     */

264ExpandedSubBlockStart.gifContractedSubBlock.gif    public String nextTo(char d) {
265        StringBuffer sb = new StringBuffer();
266ExpandedSubBlockStart.gifContractedSubBlock.gif        for (;;) {
267            char c = next();
268ExpandedSubBlockStart.gifContractedSubBlock.gif            if (c == d || c == 0 || c == '\n' || c == '\r'{
269ExpandedSubBlockStart.gifContractedSubBlock.gif                if (c != 0{
270                    back();
271                }

272                return sb.toString().trim();
273            }

274            sb.append(c);
275        }

276    }

277
278
279ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
280     * Get the text up but not including one of the specified delimeter
281     * characters or the end of line, whichever comes first.
282     * @param delimiters A set of delimiter characters.
283     * @return A string, trimmed.
284     */

285ExpandedSubBlockStart.gifContractedSubBlock.gif    public String nextTo(String delimiters) {
286        char c;
287        StringBuffer sb = new StringBuffer();
288ExpandedSubBlockStart.gifContractedSubBlock.gif        for (;;) {
289            c = next();
290            if (delimiters.indexOf(c) >= 0 || c == 0 ||
291ExpandedSubBlockStart.gifContractedSubBlock.gif                    c == '\n' || c == '\r'{
292ExpandedSubBlockStart.gifContractedSubBlock.gif                if (c != 0{
293                    back();
294                }

295                return sb.toString().trim();
296            }

297            sb.append(c);
298        }

299    }

300
301
302ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
303     * Get the next value. The value can be a Boolean, Double, Integer,
304     * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
305     * @throws JSONException If syntax error.
306     *
307     * @return An object.
308     */

309ExpandedSubBlockStart.gifContractedSubBlock.gif    public Object nextValue() throws JSONException {
310        char c = nextClean();
311        String s;
312
313ExpandedSubBlockStart.gifContractedSubBlock.gif        switch (c) {
314            case '"':
315            case '\'':
316                return nextString(c);
317            case '{':
318                back();
319                return new JSONObject(this);
320            case '[':
321            case '(':
322                back();
323                return new JSONArray(this);
324        }

325
326ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//*
327         * Handle unquoted text. This could be the values true, false, or
328         * null, or it can be a number. An implementation (such as this one)
329         * is allowed to also accept non-standard forms.
330         *
331         * Accumulate characters until we reach the end of the text or a
332         * formatting character.
333         */

334
335        StringBuffer sb = new StringBuffer();
336        char b = c;
337ExpandedSubBlockStart.gifContractedSubBlock.gif        while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
338            sb.append(c);
339            c = next();
340        }

341        back();
342
343ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//*
344         * If it is true, false, or null, return the proper value.
345         */

346
347        s = sb.toString().trim();
348ExpandedSubBlockStart.gifContractedSubBlock.gif        if (s.equals("")) {
349            throw syntaxError("Missing value");
350        }

351ExpandedSubBlockStart.gifContractedSubBlock.gif        if (s.equalsIgnoreCase("true")) {
352            return Boolean.TRUE;
353        }

354ExpandedSubBlockStart.gifContractedSubBlock.gif        if (s.equalsIgnoreCase("false")) {
355            return Boolean.FALSE;
356        }

357ExpandedSubBlockStart.gifContractedSubBlock.gif        if (s.equalsIgnoreCase("null")) {
358            return JSONObject.NULL;
359        }

360
361ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//*
362         * If it might be a number, try converting it. We support the 0- and 0x-
363         * conventions. If a number cannot be produced, then the value will just
364         * be a string. Note that the 0-, 0x-, plus, and implied string
365         * conventions are non-standard. A JSON parser is free to accept
366         * non-JSON forms as long as it accepts all correct JSON forms.
367         */

368
369ExpandedSubBlockStart.gifContractedSubBlock.gif        if ((b >= '0' && b <= '9'|| b == '.' || b == '-' || b == '+'{
370ExpandedSubBlockStart.gifContractedSubBlock.gif            if (b == '0'{
371                if (s.length() > 2 &&
372ExpandedSubBlockStart.gifContractedSubBlock.gif                        (s.charAt(1== 'x' || s.charAt(1== 'X')) {
373ExpandedSubBlockStart.gifContractedSubBlock.gif                    try {
374                        return new Integer(Integer.parseInt(s.substring(2),
375                                16));
376ExpandedSubBlockStart.gifContractedSubBlock.gif                    }
 catch (Exception e) {
377ExpandedSubBlockStart.gifContractedSubBlock.gif                        /**//* Ignore the error */
378                    }

379ExpandedSubBlockStart.gifContractedSubBlock.gif                }
 else {
380ExpandedSubBlockStart.gifContractedSubBlock.gif                    try {
381                        return new Integer(Integer.parseInt(s, 8));
382ExpandedSubBlockStart.gifContractedSubBlock.gif                    }
 catch (Exception e) {
383ExpandedSubBlockStart.gifContractedSubBlock.gif                        /**//* Ignore the error */
384                    }

385                }

386            }

387ExpandedSubBlockStart.gifContractedSubBlock.gif            try {
388                return new Integer(s);
389ExpandedSubBlockStart.gifContractedSubBlock.gif            }
 catch (Exception e) {
390ExpandedSubBlockStart.gifContractedSubBlock.gif                try {
391                    return new Long(s);
392ExpandedSubBlockStart.gifContractedSubBlock.gif                }
 catch (Exception f) {
393ExpandedSubBlockStart.gifContractedSubBlock.gif                    try {
394                        return new Double(s);
395ExpandedSubBlockStart.gifContractedSubBlock.gif                    }
  catch (Exception g) {
396                        return s;
397                    }

398                }

399            }

400        }

401        return s;
402    }

403
404
405ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
406     * Skip characters until the next character is the requested character.
407     * If the requested character is not found, no characters are skipped.
408     * @param to A character to skip to.
409     * @return The requested character, or zero if the requested character
410     * is not found.
411     */

412ExpandedSubBlockStart.gifContractedSubBlock.gif    public char skipTo(char to) {
413        char c;
414        int index = this.myIndex;
415ExpandedSubBlockStart.gifContractedSubBlock.gif        do {
416            c = next();
417ExpandedSubBlockStart.gifContractedSubBlock.gif            if (c == 0{
418                this.myIndex = index;
419                return c;
420            }

421        }
 while (c != to);
422        back();
423        return c;
424    }

425
426
427ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
428     * Skip characters until past the requested string.
429     * If it is not found, we are left at the end of the source.
430     * @param to A string to skip past.
431     */

432ExpandedSubBlockStart.gifContractedSubBlock.gif    public boolean skipPast(String to) {
433        this.myIndex = this.mySource.indexOf(to, this.myIndex);
434ExpandedSubBlockStart.gifContractedSubBlock.gif        if (this.myIndex < 0{
435            this.myIndex = this.mySource.length();
436            return false;
437        }
 
438        this.myIndex += to.length();
439        return true;
440
441    }

442
443
444ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
445     * Make a JSONException to signal a syntax error.
446     *
447     * @param message The error message.
448     * @return  A JSONException object, suitable for throwing
449     */

450ExpandedSubBlockStart.gifContractedSubBlock.gif    public JSONException syntaxError(String message) {
451        return new JSONException(message + toString());
452    }

453
454
455ExpandedSubBlockStart.gifContractedSubBlock.gif    /** *//**
456     * Make a printable string of this JSONTokener.
457     *
458     * @return " at character [this.myIndex] of [this.mySource]"
459     */

460ExpandedSubBlockStart.gifContractedSubBlock.gif    public String toString() {
461        return " at character " + this.myIndex + " of " + this.mySource;
462    }

463}

 

Delphi源代码:

{
Copyright (c) 2002 JSON.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

The Software shall be used for Good, not Evil.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
}

{
 * A JSONTokener takes a source string and extracts characters and tokens from
 * it. It is used by the JSONObject and JSONArray constructors to parse
 * JSON source strings.
 * @author JSON.org
 * @version 2
 
}
unit  JSONTokener;

interface

uses
    SysUtils,
    StrUtils,
    AutoPtr,
      JSONException;

type
    TJSONTokener 
=   class
    
private
        fMyIndex: Integer;
        fMySource: 
string ;
    
public
        
constructor  Create(aMySource:  string );  virtual ;
        
procedure  Back;
        
class   function  DeHexChar(c: Char): Integer;
        
function  More: Boolean;
        
function  Next: Char;  overload ;
        
function  Next(c: Char): Char;  overload ;
        
function  Next(n: Integer):  string overload ;
        
function  SyntaxError(aMsg:  string ): EJSONException;
        
function  ToString:  string override ;
        
function  NextClean: Char;
        
function  NextString(quote: Char):  string ;
        
function  NextTo(d: Char):  string overload ;
        
function  NextTo(delimiters:  string ):  string overload ;
        
function  NextValue: IAutoPtr < TObject > ;
        
function  SkipTo(toc: Char): Char;
        
function  SkipPast(tos:  string ): Boolean;
    
end ;

implementation

uses
    StringObject,
    BooleanObject,
    IntegerObject,
    LongObject,
    DoubleObject,
    Utils,
    JSONObject,
    JSONArray;

{  TJSONTokener  }

procedure  TJSONTokener.Back;
begin
    
if  fMyIndex  >   0   then
        Dec(fMyIndex);
end ;

constructor  TJSONTokener.Create(aMySource:  string );
begin
    
inherited  Create;

    fMyIndex :
=   0 ;
    fMySource :
=  aMySource;
end ;

class   function  TJSONTokener.DeHexChar(c: Char): Integer;
begin
    
if  (c  >=   ' 0 ' and  (c  <=   ' 9 ' then
        Exit(Ord(c) 
-  Ord( ' 0 ' ));
    
if  (c  >=   ' A ' and  (c  <=   ' F ' then
        Exit(Ord(c) 
-  (Ord( ' A ' -   10 ));
    
if  (c  >=   ' a ' and  (c  <=   ' f ' then
        Exit(Ord(c) 
-  (Ord( ' a ' -   10 ));

    Result :
=   - 1 ;
end ;

function  TJSONTokener.More: Boolean;
begin
    Result :
=  fMyIndex  <  Length(fMySource);
end ;

function  TJSONTokener.Next(n: Integer):  string ;
var
    i, j: Integer;
begin
    i :
=  fMyIndex;
    j :
=  i  +  Ord(n);
    
if  j  >=  Length(fMySource)  then
        
raise  SyntaxError( ' Substring bounds error ' );

    Inc(fMyIndex, n);
    Result :
=  SubString(fMySource, i, j);
end ;

function  TJSONTokener.NextClean: Char;
var
    c: Char;
begin
    
while  True  do
    
begin
        c :
=  Next;
        
if  Ord(c)  =  Ord( ' / ' then
        
begin
            
case  Next  of
                
' / ' :
                
begin
                    
repeat
                        c :
=  Next;
                    
until  (Ord(c)  =   13 or  (Ord(c)  =   10 or  (Ord(c)  =   0 );
                
end ;

                
' * ' :
                
begin
                    
while  True  do
                    
begin
                        c :
=  Next;
                        
if  Ord(c)  =   0   then
                            
raise  SyntaxError( ' Unclosed comment ' );
                        
if  Ord(c)  =  Ord( ' * ' then
                        
begin
                            
if  Ord(Next)  =  Ord( ' / ' then
                                Break;
                            Back;
                        
end ;
                    
end ;
                
end ;
                
else   begin
                    Back;
                    Exit(
' / ' );
                
end ;
            
end ;
        
end
        
else   if  Ord(c)  =  Ord( ' # ' then
        
begin
            
repeat
                c :
=  Next;
            
until  (Ord(c)  =   13 or  (Ord(c)  =   10 or  (Ord(c)  =   0 );
        
end
        
else   if  (Ord(c)  =   0 or  (Ord(c)  >  Ord( '   ' ))  then
        
begin
            Exit(c);
        
end ;
    
end ;
end ;

function  TJSONTokener.NextString(quote: Char):  string ;
var
    c: Char;
begin
    
while  True  do
    
begin
        c :
=  Next;
        
case  c  of
            #
0 , # 13 , # 10 :
            
begin
                
raise  SyntaxError( ' Unterminated string ' );
            
end ;

            #
92 //   ' \\ '
            
begin
                c :
=  Next;
                
case  c  of
                    
' b ' : Result : =  Result  +  # 8 ;
                    
' t ' : Result : =  Result  +  # 9 ;
                    
' n ' : Result : =  Result  +  # 10 ;
                    
' f ' : Result : =  Result  +  # 12 ;
                    
' r ' : Result : =  Result  +  # 13 ;
                    
' u ' : Result : =  Result  +  Char(StrToInt( ' $ '   +  Next( 4 )));
                    
' x ' : Result : =  Result  +  Char(StrToInt( ' $ '   +  Next( 2 )));
                    
else   begin
                        Result :
=  Result  +  c;
                    
end ;
                
end ;
            
end ;

            
else   begin
                
if  Ord(c)  =  Ord(quote)  then
                    Exit;
                Result :
=  Result  +  c;
            
end ;
        
end ;
    
end ;
end ;

function  TJSONTokener.NextTo(delimiters:  string ):  string ;
var
    c: Char;
begin
    
while  True  do
    
begin
        c :
=  Next;
        
if  (Pos(c, delimiters)  >=   1 or  (Ord(c)  =   0 or
            (Ord(c) 
=   13 or  (Ord(c)  =   10 then
        
begin
            
if  Ord(c)  <>   0   then
                Break;
            Exit(Trim(Result));
        
end ;
        Result :
=  Result  +  c;
    
end ;
end ;

function  TJSONTokener.NextValue: IAutoPtr < TObject > ;
var
    c, b: Char;
    s, sb: 
string ;
begin
    c :
=  NextClean;
    
case  c  of
        
' " ' ' '' ' : Exit(TAutoPtr < TObject > .New(TStringObject.Create(NextString(c))));
        
' { ' :
        
begin
            Back;
            Exit(TAutoPtr
< TObject > .New(TJSONObject.Create(Self)));
        
end ;

        
' [ ' ' ( ' :
        
begin
            Back;
            Exit(TAutoPtr
< TObject > .New(TJSONArray.Create(Self)));
        
end ;
    
end ;

    
{
     /*
         * Handle unquoted text. This could be the values true, false, or
         * null, or it can be a number. An implementation (such as this one)
         * is allowed to also accept non-standard forms.
         *
         * Accumulate characters until we reach the end of the text or a
         * formatting character.
         */
    
}
    b :
=  c;
    
while  (Ord(c)  >=  Ord( '   ' ))  and  (Pos(c,  ' ,:]}/\"[{;=# ' <   1 do
    
begin
        sb :
=  sb  +  c;
        c :
=  Next;
    
end ;
    Back;

    
//  If it  is  true, false,  or  null, return the proper value.
    s :
=  Trim(sb);
    
if  Length(s)  =   0   then
        
raise  SyntaxError( ' Missing value ' );
    
if  LowerCase(s)  =   ' true '   then
        Exit(TAutoPtr
< TObject > .New(TBooleanObject.TRUE));
    
if  LowerCase(s)  =   ' false '   then
        Exit(TAutoPtr
< TObject > .New(TBooleanObject.FALSE));
    
if  LowerCase(s)  =   ' null '   then
        Exit(TAutoPtr
< TObject > .New(TJSONObject.NULL));

    
{
        /*
         * If it might be a number, try converting it. We support the 0- and 0x-
         * conventions. If a number cannot be produced, then the value will just
         * be a string. Note that the 0-, 0x-, plus, and implied string
         * conventions are non-standard. A JSON parser is free to accept
         * non-JSON forms as long as it accepts all correct JSON forms.
         */
    
}
    
if  ((Ord(b)  >=  Ord( ' 0 ' ))  and  (Ord(b)  <=  Ord( ' 9 ' )))
        
or  (Ord(b)  =  Ord( ' . ' ))
        
or  (Ord(b)  =  Ord( ' - ' ))
        
or  (Ord(b)  =  Ord( ' + ' ))  then
    
begin
        
if  Ord(b)  =  Ord( ' 0 ' then
        
begin
            
if  (Length(s)  >   2 and  ((s[ 2 =   ' x ' or  (s[ 2 =   ' X ' ))   then
            
begin
                
try
                    Exit(TAutoPtr
< TObject > .New(TIntegerObject.Create(
                        StrToInt(
' $ '   +  SubString(s,  2 )))));
                
except
                    
//  Ignore the error
                
end ;
            
end
            
else
            
begin
                
try
                    Exit(TAutoPtr
< TObject > .New(TIntegerObject.Create(
                        Utils.Base8(s))));
                
except

                
end ;
            
end ;
        
end ;

        
try
            Exit(TAutoPtr
< TObject > .New(TIntegerObject.Create(
                StrToInt(s))));
        
except
            
try
                Exit(TAutoPtr
< TObject > .New(TLongObject.Create(
                    StrToInt64(s))));
            
except
                
try
                    Exit(TAutoPtr
< TObject > .New(TDoubleObject.Create(
                        StrToFloat(s))));
                
except
                    Exit(TAutoPtr
< TObject > .New(TStringObject.Create(s)));
                
end ;
            
end ;
        
end ;
    
end ;

    Exit(TAutoPtr
< TObject > .New(TStringObject.Create(s)));
end ;

function  TJSONTokener.NextTo(d: Char):  string ;
var
    c: Char;
begin
    
while  True  do
    
begin
        c :
=  Next;
        
if  (Ord(c)  =  Ord(d))  or  (Ord(c)  =   0 or  (Ord(c)  =   13 or  (Ord(c)  =   10 then
        
begin
            
if  Ord(c)  <>   0   then
                Break;
            Exit(Trim(Result));
        
end ;

        Result :
=  Result  +  c;
    
end ;
end ;

function  TJSONTokener.SkipPast(tos:  string ): Boolean;
begin
    fMyIndex :
=  PosEx(tos, fMySource, fMyIndex)  -   1 ;
    
if  fMyIndex  <   0   then
    
begin
        fMyIndex :
=  Length(fMySource);
        Exit(False);
    
end ;

    Inc(fMyIndex, Length(tos));
    Result :
=  True;
end ;

function  TJSONTokener.SkipTo(toc: Char): Char;
var
    c: Char;
    index: Integer;
begin
    index :
=  fMyIndex;
    
repeat
        c :
=  Next;
        
if  Ord(c)  =   0   then
        
begin
            fMyIndex :
=  index;
            Exit(c);
        
end ;
    
until  Ord(c)  =  Ord(toc);

    Back;
    Result :
=  c;
end ;

function  TJSONTokener.SyntaxError(aMsg:  string ): EJSONException;
begin
    Result :
=  EJSONException.Create(aMsg  +  ToString);
end ;

function  TJSONTokener.ToString:  string ;
begin
    Result :
=   '  at character  '   +  IntToStr(fMyIndex)  +   '  of  '   +  fMySource;
end ;

function  TJSONTokener.Next(c: Char): Char;
var
    n: Char;
begin
    n :
=  Next;
    
if  Ord(n)  <>  Ord(c)  then
        
raise  EJSONException.Create( ' Expected '' '   +  c  +   ' '' and instead saw '' '   +  n  +   ' '' ' );

    Result :
=  n;
end ;

function  TJSONTokener.Next: Char;
var
    c: Char;
begin
    
if  More  then
    
begin
        c :
=  fMySource[fMyIndex];
        Inc(fMyIndex);
        Exit(c);
    
end ;

    Result :
=  # 0 ;
end ;

end .


转载于:https://www.cnblogs.com/felixYeou/archive/2008/09/06/1285807.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值