Skip to content

io_nats_jparse_source

Rick Hightower edited this page Jul 18, 2023 · 1 revision

io.nats.jparse.source

class diagram

CharArrayOffsetCharSource

The CharArrayOffsetCharSource class is a concrete implementation of the CharSource abstract class and the ParseConstants interface. It represents a character source backed by a character array, where the starting position of the character sequence is indicated by an offset. This class provides methods for parsing integer, long, float, and double values from the character sequence. It also includes a validation method to check if a substring represents a valid integer. Additionally, it implements an errorDetails method that generates a detailed error message based on the current character being processed and the current parsing state.

public static String debugCharDescription(int c)

public static String debugCharDescription(int c) {
    String charString;
    if (c == ' ') {
        charString = "[SPACE]";
    } else if (c == '\t') {
        charString = "[TAB]";
    } else if (c == '\n') {
        charString = "[NEWLINE]";
    } else if (c == ETX) {
        charString = "ETX";
    } else {
        charString = "'" + (char) c + "'";
    }
    charString = charString + " with an int value of " + c;
    return charString;
}

The debugCharDescription method in the CharArrayOffsetCharSource class is responsible for providing a textual description of a given character based on its ASCII value.

Here is the step-by-step description of what this method does:

  1. The method takes an integer value c as input.
  2. It initializes a variable called charString to hold the description of the character.
  3. It checks if the input character c is equal to a space character. If true, it sets charString to the string "[SPACE]".
  4. If the input character c is a tab character, it sets charString to the string "[TAB]".
  5. If the input character c is a newline character, it sets charString to the string "[NEWLINE]".
  6. If c is equal to a special character identified as ETX, it sets charString to the string "ETX".
  7. If the character c does not match any of the above conditions, it appends the character to charString by converting the ASCII value of c to a character using (char) c. For example, if c is 65, the character 'A' will be appended as "'A'".
  8. Finally, the method appends " with an int value of " and the value of c to the current value of charString.
  9. The method returns the final value of charString, which represents the description of the character based on its ASCII value. sequence diagram

@Override

public int next()

@Override
public int next() {
    if (index + 1 >= sourceEndIndex) {
        index = sourceEndIndex;
        return ETX;
    }
    return data[++index];
}

Method: next()

This method is overridden from the parent class to provide the functionality of iterating over the characters in the underlying char array source.

Steps:
  1. Check if the current index (index) incremented by 1 is greater than or equal to the end index of the source array (sourceEndIndex).
    • If true, set index to sourceEndIndex and return the ETX constant, which indicates the end of the stream.
  2. Otherwise, increment index by 1 and return the character at the updated index in the data array.

Note: The data array is the char array source, and index is a variable that keeps track of the current position in the array. The ETX constant represents the end of the stream. sequence diagram

@Override

public int findAttributeEnd()

@Override
public int findAttributeEnd() {
    int index = this.index;
    final char[] data = this.data;
    final int end = this.sourceEndIndex;
    loop: for (; index < end; index++) {
        char ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
                this.index = index;
                break loop;
        }
    }
    return index;
}

The findAttributeEnd method is defined in the CharArrayOffsetCharSource class and is used to find the end index of an attribute. Here is a step-by-step description of how the method works:

  1. The method overrides the findAttributeEnd method defined in the parent class.

  2. It initializes the local variable index with the value of the instance variable this.index. This variable represents the current index position in the character array.

  3. It creates a local variable data and assigns it the value of the instance variable this.data. This variable represents the character array from which the attribute is being extracted.

  4. It creates a local variable end and assigns it the value of the instance variable this.sourceEndIndex. This variable represents the end index of the character array.

  5. It enters a loop that iterates from the current index position (index) to the end index (end) of the character array.

  6. Within each iteration of the loop, it retrieves the character at the current index position (index) from the character array and assigns it to the variable ch.

  7. It checks the value of ch using a switch statement.

  8. If ch matches any of the case values NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, or ATTRIBUTE_SEP, it updates the instance variable this.index with the value of index and breaks out of the loop labeled loop.

  9. After the loop ends, it returns the value of index, which represents the end index of the attribute.

In summary, the findAttributeEnd method iterates through a character array starting from the current index position and looks for specific characters that indicate the end of an attribute. Once a matching character is found, it updates the instance variable this.index and returns the end index. sequence diagram

@Override

public boolean findChar(char c)

@Override
public boolean findChar(char c) {
    int index = this.index;
    final char[] data = this.data;
    final int end = sourceEndIndex;
    for (; index < end; index++) {
        if (data[index] == c) {
            this.index = index;
            return true;
        }
    }
    return false;
}

The findChar method is used to search for a specific character within a character array. Here is a step-by-step description of what the method does:

  1. The method receives a character c as a parameter.
  2. It assigns the current index of the CharArrayOffsetCharSource object to the local variable index.
  3. It retrieves the character array data from the CharArrayOffsetCharSource object.
  4. It retrieves the end index of the source from the CharArrayOffsetCharSource object and assigns it to the local variable end.
  5. It starts a loop that iterates from the current index index until the end index end.
  6. Within each iteration, it checks if the character at position index within the data array is equal to the character c.
  7. If a match is found, it updates the current index of the CharArrayOffsetCharSource object to the value of index and returns true.
  8. If no match is found after iterating through the entire array, it simply returns false.
  9. The method is marked as @Override, indicating that it overrides a method from a superclass or interface.

Overall, the findChar method performs a linear search for a specific character c within the character array data. It updates the current index of the CharArrayOffsetCharSource object if a match is found and returns true. Otherwise, it returns false indicating that the character was not found. sequence diagram

@Override

public void checkForJunk()

@Override
public void checkForJunk() {
    int index = this.index;
    final char[] data = this.data;
    final int end = this.sourceEndIndex;
    int ch = ETX;
    for (; index < end; index++) {
        ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                throw new UnexpectedCharacterException("Junk", "Unexpected extra characters", this);
        }
    }
}

The checkForJunk method, defined in the io.nats.jparse.source.CharArrayOffsetCharSource class, is used to check for any junk characters in the provided character array.

Here is a step-by-step description of what the method does:

  1. It starts by initializing variables: index with the current index position in the character array, data with the provided character array, end with the end index of the character array, and ch with the ASCII value of ETX (End-of-Text).

  2. It enters a for loop that iterates from the current index to the end index of the character array.

  3. Inside the loop, it assigns the value of data[index] to ch, which represents the current character being checked.

  4. It uses a switch statement to check the value of ch against predefined cases. The cases being checked are:

    a) NEW_LINE_WS: Represents a new line whitespace character. b) CARRIAGE_RETURN_WS: Represents a carriage return whitespace character. c) TAB_WS: Represents a tab whitespace character. d) SPACE_WS: Represents a space whitespace character.

    If ch matches any of the above cases, the loop continues to the next iteration without executing any further code. This means that if the current character is a whitespace character, it is considered valid and not classified as junk.

  5. If the value of ch does not match any of the cases above, it means that an unexpected character (considered as junk) has been encountered in the character array. In this case, an UnexpectedCharacterException is thrown with the message "Junk" and "Unexpected extra characters". The this reference, representing the current instance of the CharArrayOffsetCharSource class, is passed as an argument to the exception.

  6. The for loop continues to the next iteration, and steps 3-5 are repeated until all characters in the character array have been checked.

By the end of the method, if no UnexpectedCharacterException is thrown, it means that there are no junk characters found in the provided character array. sequence diagram

@Override

public int nextSkipWhiteSpace()

@Override
public int nextSkipWhiteSpace() {
    int index = this.index + 1;
    final char[] data = this.data;
    final int endIndex = sourceEndIndex;
    int ch = ETX;
    loop: for (; index < endIndex; index++) {
        ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                break loop;
        }
    }
    this.index = index;
    return index == endIndex ? ETX : ch;
}

The nextSkipWhiteSpace method is defined in the CharArrayOffsetCharSource class in the io.nats.jparse.source package.

This method is used to skip white space characters in the data array starting from the current index. It returns the index of the next non-white space character, or ETX (end of text) if there are no more characters.

Here is a step-by-step description of what the method does:

  1. Increment index by 1 to start from the next character.
  2. Store the reference to the data array in a local variable named data.
  3. Store the value of sourceEndIndex in a local variable named endIndex.
  4. Create a variable ch and initialize it with the ETX value.
  5. Start a loop that will iterate from the current index until the endIndex.
  6. Inside the loop, assign the character at data[index] to ch.
  7. Use a switch statement to check the value of ch.
    • If ch is equal to NEW_LINE_WS or CARRIAGE_RETURN_WS or TAB_WS or SPACE_WS, continue to the next iteration of the loop.
    • Otherwise, break out of the loop.
  8. Update the index with the value of index.
  9. Return ETX if the index is equal to endIndex, otherwise return the value of ch.

This method effectively skips any white space characters (including new lines, carriage returns, tabs, and spaces) in the data array until a non-white space character is encountered. It then returns the index of that non-white space character. If there are no more characters after skipping white space, it returns the ETX value. sequence diagram

@Override

public char skipWhiteSpace()

@Override
public char skipWhiteSpace() {
    int index = this.index;
    final char[] data = this.data;
    final int endIndex = sourceEndIndex;
    char ch;
    loop: for (; index < endIndex; index++) {
        ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                break loop;
        }
    }
    this.index = index;
    return data[index];
}

The skipWhiteSpace method in the CharArrayOffsetCharSource class is used to skip any white space characters (spaces, tabs, new lines, and carriage returns) in the character array.

Here is a step-by-step description of what the method is doing:

  1. It first initializes a local variable index with the current value of this.index, which represents the current position in the character array.
  2. It also initializes a local variable data with the reference to the character array this.data that contains the source data.
  3. It gets the endIndex from the sourceEndIndex instance variable, which represents the end position in the character array.
  4. It declares a variable ch to store the current character being examined.
  5. It enters a loop that iterates over the character array starting from the current index till the endIndex.
  6. Inside the loop, it checks the character at the current index data[index] against a set of white space characters: NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, and SPACE_WS.
  7. If the character matches any of the white space characters, the loop continues to the next iteration without performing any action.
  8. If the character does not match any of the white space characters, it breaks out of the loop using the break loop; statement.
  9. After the loop completes, it updates the index instance variable with the current index value, representing the new position after skipping white space.
  10. Finally, it returns the character at that position data[index] from the character array.

So, the skipWhiteSpace method essentially advances the position in the character array to the next non-white space character and returns that character. sequence diagram

@Override

public String toEncodedStringIfNeeded(int startIndex, int endIndex)

@Override
public String toEncodedStringIfNeeded(int startIndex, int endIndex) {
    final int start = startIndex + sourceStartIndex;
    final int end = endIndex + sourceStartIndex;
    if (CharArrayUtils.hasEscapeChar(data, start, end)) {
        return getEncodedString(startIndex, endIndex);
    } else {
        return this.getString(startIndex, endIndex);
    }
}

The toEncodedStringIfNeeded method in the io.nats.jparse.source.CharArrayOffsetCharSource class is used to convert a portion of a character array into a string representation if it contains escape characters.

Here is a step-by-step description of what the method does:

  1. The method overrides the toEncodedStringIfNeeded method from the ancestor class.

  2. The method takes two parameters - startIndex and endIndex, which denote the range of characters to be converted to a string.

  3. It calculates the actual start index and end index within the data character array by adding the startIndex and endIndex to the sourceStartIndex instance variable.

  4. It checks if the portion of the character array from the calculated start index to end index (inclusive) contains any escape characters using the CharArrayUtils.hasEscapeChar method.

  5. If the portion contains escape characters, it calls the getEncodedString method with the startIndex and endIndex parameters to obtain the encoded string representation.

  6. If the portion does not contain any escape characters, it calls the getString method with the startIndex and endIndex parameters to obtain the regular string representation.

  7. Finally, it returns the obtained string representation either with escape characters encoded or without any encoding based on the presence of escape characters within the portion of the character array specified by the startIndex and endIndex. sequence diagram

@Override

public NumberParseResult findEndOfNumberFast()

@Override
public NumberParseResult findEndOfNumberFast() {
    int i = index + 1;
    char ch = 0;
    final char[] data = this.data;
    final int endIndex = this.sourceEndIndex;
    for (; i < endIndex; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i - sourceStartIndex, false);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case DECIMAL_POINT:
                index = i;
                return findEndOfFloatFast();
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponentFast();
            default:
                throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
        }
    }
    index = i;
    return new NumberParseResult(i - sourceStartIndex, false);
}

The method findEndOfNumberFast in the class io.nats.jparse.source.CharArrayOffsetCharSource is used to find the end position of a number within a character array.

Here is a step-by-step breakdown of what this method does:

  1. It initializes the local variable i to the value of index + 1.

  2. It initializes the local variable ch to 0.

  3. It assigns the value of data (a char array) to the local variable data.

  4. It assigns the value of sourceEndIndex (the end index of the source) to the local variable endIndex.

  5. It starts a loop from i until it reaches endIndex.

  6. Inside the loop, it retrieves the character at index i from the data array and assigns it to ch.

  7. It uses a switch statement to handle different cases based on the value of ch.

    • If ch matches any of the specified cases (NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, ARRAY_END_TOKEN), it updates the value of index to i and returns a new NumberParseResult object with the length of the number (i - sourceStartIndex) and a boolean indicating that the number does not have a decimal point or exponent.

    • If ch matches any digit character (NUM_0, NUM_1, NUM_2, ..., NUM_9), it continues to the next iteration of the loop.

    • If ch matches the decimal point character (DECIMAL_POINT), it updates the value of index to i and calls the findEndOfFloatFast method to find the end of a floating-point number.

    • If ch matches the exponent marker characters (EXPONENT_MARKER, EXPONENT_MARKER2), it updates the value of index to i and calls the parseFloatWithExponentFast method to parse the number with exponent notation.

    • If none of the above cases match, it throws an IllegalStateException with an error message indicating the unexpected character and its index.

  8. After the loop ends, it updates the value of index to i.

  9. It returns a new NumberParseResult object with the length of the number (i - sourceStartIndex) and a boolean indicating that the number does not have a decimal point or exponent. sequence diagram

private NumberParseResult findEndOfFloatFast()

private NumberParseResult findEndOfFloatFast() {
    int i = index + 1;
    char ch = 0;
    final char[] data = this.data;
    final int endIndex = this.sourceEndIndex;
    for (; i < endIndex; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i - sourceStartIndex, true);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponentFast();
            default:
                throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
        }
    }
    index = i;
    return new NumberParseResult(i - sourceStartIndex, true);
}

The findEndOfFloatFast method in the io.nats.jparse.source.CharArrayOffsetCharSource class is responsible for finding the end of a float number in a JSON source.

Here is a step-by-step description of what the method does:

  1. Initialize the variable i with the value of index + 1. This indicates the starting index of the float number.
  2. Initialize the variable ch with the value 0.
  3. Get a reference to the data array and store it in a local variable.
  4. Get the endIndex of the source and store it in a local variable.
  5. Start a loop from i to endIndex.
  6. Get the character at index i from the data array and store it in the variable ch.
  7. Switch on the value of ch to perform different actions based on its type.
    • If ch is a white space character (e.g., NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS), comma (ATTRIBUTE_SEP), curly brace (OBJECT_END_TOKEN), or square bracket (ARRAY_END_TOKEN), set the index to i and return a NumberParseResult object indicating the number of characters parsed and that parsing is successful.
    • If ch is a digit character (NUM_0, NUM_1, NUM_2, ..., NUM_9), continue with the loop to parse the next character.
    • If ch is an exponent marker character (EXPONENT_MARKER, EXPONENT_MARKER2), set the index to i and call the parseFloatWithExponentFast() method to parse the number with exponent notation.
    • If ch is any other character, throw an UnexpectedCharacterException indicating that an unexpected character is encountered while parsing a JSON float number.
  8. After the loop completes, set the index to i to indicate the end index of the float number.
  9. Return a NumberParseResult object indicating the number of characters parsed and a flag indicating a successful parse.

Note: The specific values (e.g., NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, etc.) mentioned in the switch cases are assumed to be constants defined elsewhere in the code. sequence diagram

private NumberParseResult parseFloatWithExponentFast()

private NumberParseResult parseFloatWithExponentFast() {
    int i = index + 1;
    char ch = 0;
    int signOperator = 0;
    final char[] data = this.data;
    final int end = sourceEndIndex;
    for (; i < end; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i - sourceStartIndex, true);
            case MINUS:
            case PLUS:
                signOperator++;
                if (signOperator > 1) {
                    throw new IllegalStateException("Too many sign operators when parsing exponent of float");
                }
                break;
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            default:
                throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
        }
    }
    index = i;
    return new NumberParseResult(i - sourceStartIndex, true);
}

Method: parseFloatWithExponentFast()

This method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class.

Step-by-step description:

  1. Initialize a variable i with the value of index + 1.
  2. Initialize a variable ch with a value of 0.
  3. Initialize a variable signOperator with a value of 0.
  4. Get the character array data from the instance of CharArrayOffsetCharSource.
  5. Get the end index end of the character source.
  6. Enter a loop starting from i until end.
  7. Get the character at index i from the data array and assign it to ch.
  8. Enter a switch statement based on the value of ch:
    • If ch matches any of the following cases:
      • NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, or ARRAY_END_TOKEN,
      • Update the index variable to i and return a new NumberParseResult object with the difference i - sourceStartIndex and a value of true.
    • If ch matches either MINUS or PLUS,
      • Increment the signOperator variable by 1.
      • If signOperator is greater than 1, throw an IllegalStateException with the message "Too many sign operators when parsing exponent of float".
    • If ch matches any of the following cases:
      • NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, or NUM_9,
      • Continue to the next iteration of the loop.
    • If ch does not match any of the above cases, throw an IllegalStateException with the message "Unexpected character ch at index index".
  9. After the loop, update the index variable to i.
  10. Return a new NumberParseResult object with the difference i - sourceStartIndex and a value of true. sequence diagram

@Override

public int findEndOfEncodedStringFast()

@Override
public int findEndOfEncodedStringFast() {
    int i = ++index;
    final char[] data = this.data;
    final int end = sourceEndIndex;
    boolean controlChar = false;
    for (; i < end; i++) {
        char ch = data[i];
        switch(ch) {
            case CONTROL_ESCAPE_TOKEN:
                controlChar = !controlChar;
                continue;
            case STRING_END_TOKEN:
                if (!controlChar) {
                    index = i + 1;
                    return i;
                }
                controlChar = false;
                break;
            default:
                controlChar = false;
                break;
        }
    }
    throw new IllegalStateException("Unable to find closing for String");
}

The findEndOfEncodedStringFast() method, defined in the io.nats.jparse.source.CharArrayOffsetCharSource class, is used to find the closing position of an encoded string within a character array.

Here is a step-by-step description of how the method works:

  1. The method starts by incrementing the index variable by 1 and assigning its value to i.

  2. It then retrieves the character array (data) and the end index (end) from the source.

  3. The method initializes a boolean variable controlChar to false. This variable keeps track of whether a control character (such as an escape character) has been encountered.

  4. A for loop is initiated, iterating through each character in the character array, starting from index i and going up to end.

  5. Within the loop, the current character (ch) is retrieved.

  6. A switch statement is used to check the value of the current character:

    a. If the character is equal to CONTROL_ESCAPE_TOKEN, the controlChar variable is toggled (flipped) by assigning it the opposite value (true becomes false, false becomes true), and the loop continues to the next iteration.

    b. If the character is equal to STRING_END_TOKEN, and controlChar is false (indicating that it's not within a control sequence), then the method updates the index variable to be equal to i + 1, and returns the current value of i. This signifies that the closing position of the encoded string has been found.

    c. If the character does not match either of the above cases, the controlChar variable is set to false, indicating that it is not within a control sequence.

  7. If none of the characters within the loop match the conditions to find the closing position of the encoded string, the method throws an IllegalStateException with a message stating "Unable to find closing for String". This serves as an indication that the closing position could not be found.

In summary, the findEndOfEncodedStringFast() method iterates through a character array, checking each character to determine the closing position of an encoded string. It considers control characters and checks for the end token to determine when the closing position is reached. sequence diagram

private int findEndOfStringControlEncode(int i)

private int findEndOfStringControlEncode(int i) {
    final char[] data = this.data;
    final int length = data.length;
    char ch = 0;
    ch = data[i];
    switch(ch) {
        case CONTROL_ESCAPE_TOKEN:
        case STRING_END_TOKEN:
        case 'n':
        case 'b':
        case '/':
        case 'r':
        case 't':
        case 'f':
            return i;
        case 'u':
            return findEndOfHexEncoding(i);
        default:
            throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
    }
}

The findEndOfStringControlEncode method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class and takes an integer i as input. Below is a step-by-step description of what the method is doing:

  1. The method begins by declaring a local variable data, which is assigned the value of this.data. this.data refers to a char array that represents the source data being processed.
  2. A local variable length is declared and assigned the length of the data array.
  3. A local variable ch of type char is declared and initialized to 0.
  4. The character at index i of the data array is assigned to ch.
  5. A switch statement is used to perform different actions based on the value of ch.
    • If ch is equal to CONTROL_ESCAPE_TOKEN, STRING_END_TOKEN, 'n', 'b', '/', 'r', 't', or 'f', the method simply returns i. These characters represent the control escape token and various escape sequences commonly found in JSON strings.
    • If ch is equal to 'u', the method calls the findEndOfHexEncoding method with i as an argument and returns the result. This suggests that findEndOfHexEncoding is responsible for finding the end of a hexadecimal encoding, which is likely used to decode Unicode characters in the JSON string.
    • If none of the above cases match, it means that an unexpected character was encountered while trying to find the closing for a string. In this case, an UnexpectedCharacterException is thrown with a descriptive error message, including the current source (this), the unexpected character ch, and the current index i.

That concludes the step-by-step description of the findEndOfStringControlEncode method. sequence diagram

@Override

public int findEndOfEncodedString()

@Override
public int findEndOfEncodedString() {
    int i = ++index;
    final char[] data = this.data;
    final int length = data.length;
    char ch = 0;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case CONTROL_ESCAPE_TOKEN:
                i = findEndOfStringControlEncode(i + 1);
                continue;
            case STRING_END_TOKEN:
                index = i + 1;
                return i;
            default:
                if (ch >= SPACE_WS) {
                    continue;
                }
                throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
        }
    }
    throw new UnexpectedCharacterException("Parsing JSON Encoded String", "Unable to find closing for String", this, ch, i);
}

The findEndOfEncodedString method is defined in the CharArrayOffsetCharSource class in the io.nats.jparse.source package. Here is a step-by-step description of what this method does:

  1. Declare a local variable i and initialize it with the value of ++index. This increments the value of the index variable by 1 and assigns the updated value to i.
  2. Retrieve the data array from this object. This is the character array that the method operates on.
  3. Get the length of the data array and store it in the length variable.
  4. Declare a variable ch and initialize it with 0.
  5. Start a loop that iterates through the array from the current value of i to the end of the array (length).
  6. Get the character at the current index i from the data array and assign it to ch.
  7. Use a switch statement to perform different actions based on the value of ch:
    • If ch is equal to the CONTROL_ESCAPE_TOKEN constant, call the findEndOfStringControlEncode method with the argument i + 1 and assign its return value to i. This method is not provided, so we can't describe its exact behavior.
    • If ch is equal to the STRING_END_TOKEN constant, update the value of the index variable to i + 1 and return the current value of i.
    • If none of the above conditions are true, check if ch is greater than or equal to the SPACE_WS constant. If it is, continue to the next iteration of the loop.
    • If none of the conditions above are true, throw an UnexpectedCharacterException with a message indicating that an unexpected character was encountered while finding the closing of a string. The exception includes information about the current CharSource, the unexpected character ch, and its position i.
  8. If the loop completes without finding the closing of the string, throw an UnexpectedCharacterException with a message indicating that the closing for the string could not be found. The exception includes information about the current CharSource, the last character ch encountered, and its position i. sequence diagram

private int findEndOfHexEncoding(int index)

private int findEndOfHexEncoding(int index) {
    final char[] data = this.data;
    final int length = data.length;
    if (isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index])) {
        return index;
    } else {
        throw new UnexpectedCharacterException("Parsing hex encoding in a string", "Unexpected character", this);
    }
}

The method findEndOfHexEncoding is defined in the class io.nats.jparse.source.CharArrayOffsetCharSource. It takes an index as a parameter and returns an integer.

Here is a step-by-step description of what the method does:

  1. The method starts by getting the data array and its length from the current instance of CharArrayOffsetCharSource.

  2. It then checks if the character at the next index in the data array is a valid hexadecimal character (isHex). It does this repeatedly for the next 4 characters by incrementing the index for each check.

  3. If all 4 characters are valid hexadecimal characters, the method returns the current value of index.

  4. If any of the characters are not valid hexadecimal characters, the method throws an UnexpectedCharacterException. The exception message states that it occurred while parsing a hex encoding in a string, and the unexpected character is included in the message. The this reference is passed as an argument to provide additional context.

In summary, the findEndOfHexEncoding method scans the data array starting from the given index and checks if the next 4 characters form a valid hex encoding. If they do, it returns the index. If not, it throws an exception. sequence diagram

private boolean isHex(char datum)

private boolean isHex(char datum) {
    switch(datum) {
        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F':
        case 'a':
        case 'b':
        case 'c':
        case 'd':
        case 'e':
        case 'f':
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            return true;
        default:
            return false;
    }
}

The isHex method in the io.nats.jparse.source.CharArrayOffsetCharSource class is used to determine whether a given character is a hexadecimal digit. Here is a step-by-step description of what the method does:

  1. The method takes a single parameter datum, which represents the character to be tested.

  2. The method uses a switch statement to check the value of the datum character.

  3. If the datum character is any of the following characters: 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', or '9', then the method returns true. These characters represent valid hexadecimal digits.

  4. If the datum character is not one of the specified hexadecimal digits, the default case is executed, and the method returns false.

  5. So overall, the isHex method determines whether a character is a hexadecimal digit by checking if it falls within the specified range of valid hexadecimal characters. If the character is within the range, the method returns true; otherwise, it returns false. sequence diagram

@Override

public int findEndString()

@Override
public int findEndString() {
    int i = ++index;
    final char[] data = this.data;
    final int length = data.length;
    char ch = 0;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case STRING_END_TOKEN:
                index = i;
                return i;
            default:
                if (ch >= SPACE_WS) {
                    continue;
                }
                throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
        }
    }
    throw new UnexpectedCharacterException("Parsing JSON String", "Unable to find closing for String", this, ch, i);
}

This findEndString method is defined in the CharArrayOffsetCharSource class and it overrides the same method from the superclass.

Here is a step-by-step description of what this method does:

  1. It starts by incrementing the index variable.
  2. It retrieves the data array and its length from the class instance.
  3. It declares a ch variable and sets it to 0.
  4. It enters a loop from the incremented index up to the length of the data array.
  5. Inside the loop, it assigns the current character of the data array to ch.
  6. It checks for a switch case where ch is equal to the STRING_END_TOKEN.
    • If so, it updates the index variable to the current index and returns the index.
    • If not, it continues to the next step.
  7. It then checks if ch is greater than or equal to SPACE_WS. If true, it continues to the next iteration of the loop.
  8. If the character doesn't match the switch case and is not greater than SPACE_WS, it throws an UnexpectedCharacterException with the appropriate message, passing in this object, ch, and the current index.
  9. If the loop completes without finding a match, it throws an UnexpectedCharacterException with the appropriate message, passing in this object, ch, and the current index.

Note: The specific values for STRING_END_TOKEN and SPACE_WS are not included in the code snippet provided and may be defined elsewhere in the codebase or imported from another class or module. sequence diagram

@Override

public NumberParseResult findEndOfNumber()

@Override
public NumberParseResult findEndOfNumber() {
    final char startCh = getCurrentChar();
    final int startIndex = index;
    char ch = startCh;
    int i = index + 1;
    final char[] data = this.data;
    final int endIndex = this.sourceEndIndex;
    loop: for (; i < endIndex; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                break loop;
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case DECIMAL_POINT:
                if (startCh == MINUS) {
                    final int numLenSoFar = i - startIndex;
                    if (numLenSoFar == 1) {
                        throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
                    }
                }
                index = i;
                return findEndOfFloat();
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponent();
            default:
                throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
        }
    }
    index = i;
    final int numLength = i - startIndex;
    switch(startCh) {
        case NUM_0:
            if (numLength != 1) {
                throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a 0 ", this, startCh, startIndex);
            }
            break;
        case PLUS:
            throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a plus ", this, startCh, startIndex);
        case MINUS:
            switch(numLength) {
                case 1:
                    throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't be only a minus, number is missing", this, startCh, startIndex);
                case 2:
                    break;
                default:
                    if (data[startIndex + 1] == NUM_0) {
                        throw new UnexpectedCharacterException("Parsing JSON Int Number", "0 can't be after minus sign", this, startCh, startIndex);
                    }
            }
    }
    return new NumberParseResult(i - this.sourceStartIndex, false);
}

The method findEndOfNumber in the class io.nats.jparse.source.CharArrayOffsetCharSource is responsible for finding the end of a number while parsing JSON data. Here is the step-by-step description of what this method does based on its code:

  1. It retrieves the current character from the source and assigns it to the variable startCh.
  2. It sets the starting index to the current index.
  3. It initializes the variable ch with the value of startCh and increments the variable i by 1.
  4. It retrieves the character array data and the end index endIndex from the source.
  5. It enters a loop that iterates over the characters from i to endIndex.
  6. For each character ch in the loop:
    • If the character is one of the following: NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, or ARRAY_END_TOKEN, the loop breaks.
    • If the character is one of the digits NUM_0 to NUM_9, the loop continues.
    • If the character is a DECIMAL_POINT and the startCh is MINUS, it checks if the length of the number is 1. If it is, it throws an exception. Then, it sets the current index to i and returns the result of calling the findEndOfFloat method.
    • If the character is an EXPONENT_MARKER or an EXPONENT_MARKER2, it sets the current index to i and returns the result of calling the parseFloatWithExponent method.
    • If none of the above conditions match, it throws an exception.
  7. It sets the current index to i.
  8. It calculates the length of the number by subtracting the starting index from i and assigns it to numLength.
  9. It checks the value of the startCh character:
    • If it is NUM_0, it checks if numLength is not equal to 1. If it is not, it throws an exception.
    • If it is PLUS, it throws an exception.
    • If it is MINUS, it checks the value of numLength:
      • If it is 1, it throws an exception.
      • If it is 2, it continues.
      • If it is greater than 2 and the character following the MINUS is NUM_0, it throws an exception.
  10. It creates a new NumberParseResult object with the length of the number (i - this.sourceStartIndex) and the value false.
  11. It returns the NumberParseResult object. sequence diagram

private NumberParseResult findEndOfFloat()

private NumberParseResult findEndOfFloat() {
    int i = index + 1;
    char ch = (char) next();
    if (!isNumber(ch)) {
        throw new UnexpectedCharacterException("Parsing float part of number", "After decimal point expecting number but got", this, ch, this.index);
    }
    final char[] data = this.data;
    final int endIndex = this.sourceEndIndex;
    for (; i < endIndex; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i - sourceStartIndex, true);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponent();
            default:
                throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
        }
    }
    index = i;
    return new NumberParseResult(i - sourceStartIndex, true);
}

The method findEndOfFloat in the CharArrayOffsetCharSource class is used to find the end of a floating-point number in a JSON input string. Here is a step-by-step description of what the method does:

  1. The method initializes a local variable i to the value of index + 1 and retrieves the next character ch from the input stream using the next() method.

  2. It checks if the character ch is not a valid number character. If it's not, it throws an UnexpectedCharacterException, indicating that a number was expected after the decimal point but a different character was encountered.

  3. The method then retrieves the underlying character array data and the end index of the source string.

  4. It enters a loop that iterates from i to endIndex.

  5. Inside the loop, the method checks the current character ch against a series of predefined characters that can signal the end of a floating-point number. These characters include whitespace characters (NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS), attribute and array separators (ATTRIBUTE_SEP, ARRAY_SEP), and object and array end tokens (OBJECT_END_TOKEN, ARRAY_END_TOKEN). If a match is found, the method updates the index variable to the current value of i and returns a new NumberParseResult object containing the length of the parsed number as i - sourceStartIndex and a flag indicating that the number is complete (true).

  6. If the current character ch is not one of the predefined end tokens, the method checks if it's a digit (NUM_0 to NUM_9). If it is, the loop continues to the next iteration. This allows the method to handle numbers with digits after the decimal point.

  7. If the current character ch is an exponent marker (EXPONENT_MARKER or EXPONENT_MARKER2), the method updates the index variable to the current value of i and returns the result of calling the parseFloatWithExponent() method. This method handles parsing floating-point numbers with exponent notation.

  8. If none of the above conditions are met, the method throws an UnexpectedCharacterException, indicating that an unexpected character was encountered while parsing the JSON float number.

  9. After the loop completes without finding an end token, the method updates the index variable to the current value of i and returns a new NumberParseResult object containing the length of the parsed number as i - sourceStartIndex and a flag indicating that the number is complete (true). sequence diagram

private boolean isNumber(final char ch)

private boolean isNumber(final char ch) {
    switch(ch) {
        case NUM_0:
        case NUM_1:
        case NUM_2:
        case NUM_3:
        case NUM_4:
        case NUM_5:
        case NUM_6:
        case NUM_7:
        case NUM_8:
        case NUM_9:
            return true;
        default:
            return false;
    }
}

The isNumber method in the CharArrayOffsetCharSource class is used to determine whether a given character is a number. Here is a step-by-step description of how the method works:

  1. The method takes a char parameter called ch.

  2. It uses a switch statement to check the value of the ch character.

  3. The case statements in the switch statement represent the numbers 0 to 9.

  4. If the value of ch matches any of the cases (i.e., it is a number), the method returns true.

  5. If the value of ch does not match any of the cases (i.e., it is not a number), the method returns false.

That's the step-by-step description of how the isNumber method in the CharArrayOffsetCharSource class works. sequence diagram

private NumberParseResult parseFloatWithExponent()

private NumberParseResult parseFloatWithExponent() {
    char ch = (char) next();
    if (!isNumberOrSign(ch)) {
        throw new UnexpectedCharacterException("Parsing exponent part of float", "After exponent expecting number or sign but got", this, ch, this.index);
    }
    if (isSign(ch)) {
        ch = (char) next();
        if (!isNumber(ch)) {
            throw new UnexpectedCharacterException("Parsing exponent part of float after sign", "After sign expecting number but got", this, ch, this.index);
        }
    }
    int i = index + 1;
    final char[] data = this.data;
    final int endIndex = this.sourceEndIndex;
    for (; i < endIndex; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i - sourceStartIndex, true);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            default:
                throw new UnexpectedCharacterException("Parsing Float with exponent", "Unable to find closing for Number", this, ch, i);
        }
    }
    index = i;
    return new NumberParseResult(i - sourceStartIndex, true);
}

The method parseFloatWithExponent in the CharArrayOffsetCharSource class is used to parse a floating-point number with an exponent. Below is a step-by-step description of what the method does:

  1. The method starts by fetching the next character from the input stream and assigns it to the variable ch.
  2. It checks if the character ch is a valid number or sign character using the isNumberOrSign method. If it is not, it throws an UnexpectedCharacterException with an appropriate error message.
  3. If the character ch is a sign character, it fetches the next character and assigns it to ch. If the next character is not a number, it throws an UnexpectedCharacterException with an appropriate error message.
  4. It initializes a variable i with the value of index + 1, which represents the next index to start parsing at.
  5. It assigns the internal character array data from the CharArrayOffsetCharSource instance to a local variable data.
  6. It assigns the value of sourceEndIndex to a local variable endIndex, which represents the end index of the source.
  7. It enters a for loop that iterates from i to endIndex.
  8. Inside the loop, it assigns the character at index i in the data array to ch.
  9. It checks if ch is one of the following characters: NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, or ARRAY_END_TOKEN. If it is, it updates the index variable to i and returns a new NumberParseResult object with the length of the parsed number (i - sourceStartIndex) and true indicating success.
  10. If ch is one of the digit characters NUM_0 to NUM_9, it continues the loop iteration without any special action.
  11. If ch does not match any of the above cases, it throws an UnexpectedCharacterException with an appropriate error message.
  12. After the loop exits, it updates the index variable to i and returns a new NumberParseResult object with the length of the parsed number (i - sourceStartIndex) and true indicating success.

Overall, the method iterates through the characters starting from the initial index and checks if each character is a valid part of the exponent part of a floating-point number. It stops parsing when it encounters a character that is not part of the exponent or reaches the end of the input. sequence diagram

private boolean isNumberOrSign(char ch)

private boolean isNumberOrSign(char ch) {
    switch(ch) {
        case NUM_0:
        case NUM_1:
        case NUM_2:
        case NUM_3:
        case NUM_4:
        case NUM_5:
        case NUM_6:
        case NUM_7:
        case NUM_8:
        case NUM_9:
        case MINUS:
        case PLUS:
            return true;
        default:
            return false;
    }
}

isNumberOrSign Method

The isNumberOrSign method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class. It is a private method that takes a single character as input and returns a boolean value.

Purpose

The purpose of this method is to determine whether a given character is a number or a mathematical sign (either a minus or plus symbol).

Method Body

The method contains a switch-case statement that checks the input character against several predefined constants representing the digits 0-9, as well as the minus and plus signs.

  • If the input character matches any of these constants, the method will return true, indicating that the character is a number or a sign.
  • If the input character does not match any of the constants, the method will return false, indicating that the character is not a number or a sign.

Here is the step-by-step description of the isNumberOrSign method based on its body:

  1. Declare a private boolean method named isNumberOrSign that takes a single character ch as input.

  2. Start a switch-case statement to check the value of ch.

  3. In each case, compare the value of ch to the following constants:

    • NUM_0, representing the character '0'
    • NUM_1, representing the character '1'
    • NUM_2, representing the character '2'
    • NUM_3, representing the character '3'
    • NUM_4, representing the character '4'
    • NUM_5, representing the character '5'
    • NUM_6, representing the character '6'
    • NUM_7, representing the character '7'
    • NUM_8, representing the character '8'
    • NUM_9, representing the character '9'
    • MINUS, representing the minus sign '-'
    • PLUS, representing the plus sign '+'
  4. If ch matches any of the above constants, return true to indicate that ch is a number or a sign.

  5. If ch does not match any of the above constants, return false to indicate that ch is not a number or a sign.

  6. End the method. sequence diagram

private boolean isSign(char ch)

private boolean isSign(char ch) {
    switch(ch) {
        case MINUS:
        case PLUS:
            return true;
        default:
            return false;
    }
}

The isSign method in the io.nats.jparse.source.CharArrayOffsetCharSource class is used to determine whether a given character is a sign symbol. It follows these steps:

  1. The method takes a character ch as a parameter.
  2. It enters a switch statement, which checks the value of ch.
  3. If ch is equal to the MINUS constant or the PLUS constant (presumably defined in the class or imported from another class), the method returns true.
  4. If ch does not match any of the case values, the method returns false.

To summarize, the isSign method checks if a character is a sign symbol (- or +) and returns true if it is, or false if it is not. sequence diagram

@Override

public int findFalseEnd()

@Override
public int findFalseEnd() {
    if (this.data[++index] == 'a' && this.data[++index] == 'l' && this.data[++index] == 's' && this.data[++index] == 'e') {
        return ++index - sourceStartIndex;
    } else {
        throw new UnexpectedCharacterException("Parsing JSON False Boolean", "Unexpected character", this);
    }
}

The findFalseEnd method in the io.nats.jparse.source.CharArrayOffsetCharSource class is defined as follows:

  1. The method starts by incrementing the index variable and checks if the character at the updated index is equal to 'a'.
  2. If the character is 'a', the method then increments the index variable again and checks if the character at the updated index is equal to 'l'.
  3. If the character is 'l', the method again increments the index variable and checks if the character at the updated index is equal to 's'.
  4. If the character is 's', the method once more increments the index variable and checks if the character at the updated index is equal to 'e'.
  5. If all of the characters 'a', 'l', 's', and 'e' are found consecutively, the method returns the value of the incremented index variable minus the sourceStartIndex variable.
  6. If any of the characters are not found consecutively or the end of the source is reached before finding the complete sequence, an UnexpectedCharacterException is thrown, with the message "Parsing JSON False Boolean" and "Unexpected character", and the instance of the CharArrayOffsetCharSource class is passed as an argument to the exception. sequence diagram

@Override

public int findTrueEnd()

@Override
public int findTrueEnd() {
    if (this.data[++index] == 'r' && this.data[++index] == 'u' && this.data[++index] == 'e') {
        return ++index - sourceStartIndex;
    } else {
        throw new UnexpectedCharacterException("Parsing JSON True Boolean", "Unexpected character", this);
    }
}

The method findTrueEnd is implemented in the class io.nats.jparse.source.CharArrayOffsetCharSource. Its purpose is to find the end position of a boolean value "true" within a JSON source string.

Here is a step-by-step description of what the method does:

  1. Increment the index value by 1 and check if the character at the new index position in the data array is equal to 'r'.
  2. If the character at the new index position is 'r', increment the index value by 1 again and check if the character at the new index position is equal to 'u'.
  3. If the character at the new index position is 'u', increment the index value by 1 once more and check if the character at the new index position is equal to 'e'.
  4. If all the characters 'r', 'u', and 'e' are found one after another, it means the end of the boolean value "true" has been found.
    • Return the value of ++index - sourceStartIndex, which represents the length of the substring containing the boolean value "true".
  5. If any of the characters is not found in the expected sequence, it means there is an unexpected character, and an exception of type UnexpectedCharacterException is thrown.
    • The exception message will indicate that an unexpected character was encountered while parsing the JSON True Boolean value.
    • The exception will also contain a reference to the CharArrayOffsetCharSource object that encountered the unexpected character.

This method is useful for parsing a JSON source string and identifying the end position of the boolean value "true". sequence diagram

@Override

public boolean findObjectEndOrAttributeSep()

@Override
public boolean findObjectEndOrAttributeSep() {
    int i = index;
    char ch = 0;
    final char[] data = this.data;
    final int end = sourceEndIndex;
    for (; i < end; i++) {
        ch = data[i];
        switch(ch) {
            case OBJECT_END_TOKEN:
                this.index = i + 1;
                return true;
            case ATTRIBUTE_SEP:
                this.index = i;
                return false;
        }
    }
    throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this);
}

The findObjectEndOrAttributeSep method is defined in the CharArrayOffsetCharSource class in the io.nats.jparse.source package. It is used to find the end of an object or the separator within the source data.

Here is a step-by-step description of what the method does:

  1. The method overrides the findObjectEndOrAttributeSep method defined in the superclass.
  2. It initializes the local variables i to the current index and ch to 0.
  3. It retrieves the source data array and assigns it to the local variable data.
  4. It retrieves the end index of the source and assigns it to the local variable end.
  5. It starts a loop from the current index i until the end index end.
  6. Within the loop, it retrieves the character at index i from the source data array and assigns it to ch.
  7. It then performs a switch-case on the character ch.
  8. If the character is equal to the object end token, it updates the index to i + 1, indicating that the end of the object has been found, and returns true.
  9. If the character is equal to the attribute separator, it updates the index to i, indicating that the separator has been found, and returns false.
  10. If none of the above cases match, it continues to the next iteration of the loop.
  11. If the loop completes without finding the object end or separator, it throws an UnexpectedCharacterException with an appropriate error message.
  12. The error message specifies that the error occurred while parsing an object key and while finding the object end or separator.
  13. The this reference passed to the exception constructor refers to the current CharArrayOffsetCharSource instance.

This method provides functionality to find the end of an object or the separator within the source data, allowing for efficient parsing of JSON-like data structures. sequence diagram

@Override

public boolean findCommaOrEndForArray()

@Override
public boolean findCommaOrEndForArray() {
    int i = index;
    char ch = 0;
    final char[] data = this.data;
    final int end = sourceEndIndex;
    for (; i < end; i++) {
        ch = data[i];
        switch(ch) {
            case ARRAY_END_TOKEN:
                this.index = i + 1;
                return true;
            case ARRAY_SEP:
                this.index = i;
                return false;
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this, ch, i);
        }
    }
    throw new UnexpectedCharacterException("Parsing Array", "Finding list end or separator", this);
}

The findCommaOrEndForArray() method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class. It is an override method that returns a boolean value.

Here is a step-by-step description of what the findCommaOrEndForArray() method does based on its body:

  1. Declare a variable i and initialize it with the current index value.
  2. Declare a variable ch and initialize it with 0.
  3. Assign the data array from the class to a local variable data.
  4. Extract the end value from the sourceEndIndex variable.
  5. Start a loop from the current index value (i) to the end value.
  6. Get the current character ch from data[i].
  7. Perform a switch case on ch.
    • If ch is equal to ARRAY_END_TOKEN:
      • Update the class index value to i + 1.
      • Return true to indicate that an array end has been found.
    • If ch is equal to ARRAY_SEP:
      • Update the class index value to i.
      • Return false to indicate that a comma separator has been found.
    • If ch is equal to any of the whitespace characters (NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS):
      • Continue to the next iteration of the loop.
    • If ch is not equal to any of the above characters:
      • Throw an UnexpectedCharacterException with the appropriate message, indicating that an unexpected character was found while parsing the object key or finding the object end or separator.
  8. If the loop completes without finding an array end or separator, throw an UnexpectedCharacterException with the appropriate message, indicating that an unexpected character was found while parsing the array or finding the list end or separator. sequence diagram

@Override

public int findNullEnd()

@Override
public int findNullEnd() {
    if (this.data[++index] == 'u' && this.data[++index] == 'l' && this.data[++index] == 'l') {
        return ++index - sourceStartIndex;
    } else {
        throw new UnexpectedCharacterException("Parsing JSON Null", "Unexpected character", this);
    }
}

The findNullEnd method in the io.nats.jparse.source.CharArrayOffsetCharSource class is designed to find the end of the string "null" within the provided character array.

Here is the step-by-step description of what this method does:

  1. The method starts with the index variable pointing to the current position in the character array.

  2. It checks if the character at the next position in the array after index is 'u'.

  3. If the character at the next position is 'u', it then checks if the next character after 'u' is 'l'.

  4. If the character at the next position after 'l' is also 'l', it means that the string "null" has been found.

  5. In that case, the method returns the current index value incremented by 1 and subtracted by sourceStartIndex. This calculation gives the length of the matched "null" string within the character array.

  6. If the characters 'u', 'l', and 'l' are not found in sequence, it means that an unexpected character has been encountered while parsing the JSON string.

  7. In such cases, the method throws an UnexpectedCharacterException, providing a descriptive message indicating that an unexpected character was found.

In summary, the findNullEnd method searches for the string "null" within a character array and returns the length of the matched string, or throws an exception if an unexpected character is encountered. sequence diagram

@Override

public boolean matchChars(final int startIndex, final int endIndex, CharSequence key)

@Override
public boolean matchChars(final int startIndex, final int endIndex, CharSequence key) {
    final int length = endIndex - startIndex;
    final int offset = this.sourceStartIndex;
    int idx = startIndex + offset;
    switch(length) {
        case 1:
            return key.charAt(0) == data[idx];
        case 2:
            return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1];
        case 3:
            return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2];
        case 4:
            return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(3) == data[idx + 3];
        case 5:
            return key.charAt(1) == data[idx + 1] && key.charAt(3) == data[idx + 3] && key.charAt(0) == data[idx] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
        case 6:
            return key.charAt(0) == data[idx] && key.charAt(5) == data[idx + 5] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
        case 7:
            return key.charAt(0) == data[idx] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
        case 8:
            return key.charAt(0) == data[idx] && key.charAt(7) == data[idx + 7] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(4) == data[idx + 4];
        case 9:
            return key.charAt(0) == data[idx] && key.charAt(8) == data[idx + 8] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1];
        case 10:
            return key.charAt(0) == data[idx] && key.charAt(9) == data[idx + 9] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
        case 11:
            return key.charAt(0) == data[idx] && key.charAt(10) == data[idx + 10] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
        case 12:
            return key.charAt(0) == data[idx] && key.charAt(11) == data[idx + 11] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(10) == data[idx + 10] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
        default:
            final int start = 0;
            final int end = length - 1;
            final int middle = length / 2;
            if (key.charAt(start) == data[idx] && key.charAt(end) == data[idx + end] && key.charAt(middle) == data[idx + middle]) {
                for (int i = 1; i < length; i++) {
                    if (key.charAt(i) != data[idx + i]) {
                        return false;
                    }
                }
                return true;
            } else {
                return false;
            }
    }
}

Method: matchChars

This method is defined in the class io.nats.jparse.source.CharArrayOffsetCharSource and is used to match a sequence of characters from the provided startIndex to endIndex with the given key. The method returns a boolean value indicating whether the characters match or not.

Method Signature:

public boolean matchChars(final int startIndex, final int endIndex, CharSequence key)

Parameters:

  • startIndex (int): The starting index of the character sequence to match.
  • endIndex (int): The ending index of the character sequence to match.
  • key (CharSequence): The key to match against the character sequence.

Step-by-step Description:

  1. Calculate the length of the character sequence by taking the difference between the startIndex and endIndex parameters.
  2. Get the offset from the sourceStartIndex in the class.
  3. Initialize the idx variable by adding the startIndex to the offset.
  4. Use a switch statement based on the length of the character sequence to handle different cases:
    • If the length is 1, compare the first character of the key with the character at data[idx] and return the result.
    • If the length is 2, compare the first two characters of the key with the characters at data[idx] and data[idx + 1] respectively and return the result.
    • Repeat the above steps for different cases of length 3 to 12, comparing the characters one by one.
    • For any other length, do the following:
      • Set the start, end, and middle indices based on the length.
      • Check if the first, last, and middle characters of key match the corresponding characters in data[idx] and data[idx + end] and data[idx + middle] respectively.
      • If the characters match, iterate through the remaining characters of key and compare them with the corresponding characters in data[idx + i].
      • If any character mismatch is found, return false.
      • If all characters match, return true.
  5. If none of the above cases match, return false. sequence diagram

public boolean isInteger(int startIndex, int endIndex)

public boolean isInteger(int startIndex, int endIndex) {
    int len = endIndex - startIndex;
    int offset = this.sourceStartIndex;
    final char[] digitChars = data;
    final boolean negative = (digitChars[startIndex] == '-');
    final int cmpLen = negative ? MIN_INT_STR_LENGTH : MAX_INT_STR_LENGTH;
    if (len < cmpLen)
        return true;
    if (len > cmpLen)
        return false;
    final char[] cmpStr = negative ? MIN_INT_CHARS : MAX_INT_CHARS;
    for (int i = 0; i < cmpLen; ++i) {
        int diff = digitChars[startIndex + i + offset] - cmpStr[i];
        if (diff != 0) {
            return (diff < 0);
        }
    }
    return true;
}

The method isInteger in class io.nats.jparse.source.CharArrayOffsetCharSource can be described in the following steps:

  1. Calculate the length of the input range given by endIndex - startIndex and assign it to the variable len.
  2. Set the offset of the source index to the sourceStartIndex of the object.
  3. Assign the character array data to the local variable digitChars.
  4. Check if the first character at the startIndex of digitChars is a negative sign '-' and assign the result to the negative variable.
  5. Determine the comparison length based on whether the number is negative or not. If it's negative, the comparison length should be MIN_INT_STR_LENGTH, otherwise it should be MAX_INT_STR_LENGTH, and assign the result to cmpLen.
  6. If the len is less than cmpLen, return true as it means the number cannot be an integer.
  7. If the len is greater than cmpLen, return false as it means the number cannot be an integer.
  8. Determine the comparison string based on whether the number is negative or not. If it's negative, use MIN_INT_CHARS, otherwise use MAX_INT_CHARS, and assign the result to cmpStr.
  9. Loop through each character in the comparison range (startIndex + i + offset) and compare it with the corresponding character in cmpStr.
  10. Subtract the characters from digitChars and cmpStr and store the difference in the variable diff.
  11. If diff is not equal to zero, return true if diff is less than zero, indicating that the number is less than the comparison string. Otherwise, return false as the number is greater than the comparison string.
  12. If the loop completes without returning, return true as the number is equal to the comparison string. sequence diagram

@Override

public String errorDetails(String message, int index, int ch)

@Override
public String errorDetails(String message, int index, int ch) {
    StringBuilder buf = new StringBuilder(255);
    final char[] array = data;
    buf.append(message).append("\n");
    buf.append("\n");
    buf.append("The current character read is " + debugCharDescription(ch)).append('\n');
    int line = 0;
    int lastLineIndex = 0;
    for (int i = 0; i < index && i < array.length; i++) {
        if (array[i] == '\n') {
            line++;
            lastLineIndex = i + 1;
        }
    }
    int count = 0;
    for (int i = lastLineIndex; i < array.length; i++, count++) {
        if (array[i] == '\n') {
            break;
        }
    }
    buf.append("line number " + (line + 1)).append('\n');
    buf.append("index number " + index).append('\n');
    buf.append("offset index number " + index + sourceStartIndex).append('\n');
    try {
        buf.append(new String(array, lastLineIndex, count)).append('\n');
    } catch (Exception ex) {
        try {
            int start = index = (index - 10 < 0) ? 0 : index - 10;
            buf.append(new String(array, start, index)).append('\n');
        } catch (Exception ex2) {
            buf.append(new String(array)).append('\n');
        }
    }
    for (int i = 0; i < (index - lastLineIndex); i++) {
        buf.append('.');
    }
    buf.append('^');
    return buf.toString();
}

The errorDetails method in the CharArrayOffsetCharSource class is a method that generates an error debug message with details about the error in the source code at a given index.

Here is a step-by-step description of the method:

  1. Create a new StringBuilder called buf to store the error debug message.
  2. Append the input message to buf followed by a new line character ("\n").
  3. Append an empty line to buf.
  4. Append a description of the current character being read, obtained from the debugCharDescription method, to buf.
  5. Initialize two variables: line and lastLineIndex. line is set to 0 and lastLineIndex is set to 0.
  6. Iterate through the character array data starting from index 0 up to the given index (the index of the error in the source code). a. If the current character in the array is a new line character ('\n'), increment line by 1 and update lastLineIndex to the current index plus 1.
  7. Initialize a count variable to 0.
  8. Iterate through the character array data starting from lastLineIndex up to the end of the array. a. If the current character in the array is a new line character ('\n'), break the loop. b. Otherwise, increment count by 1.
  9. Append the line number (calculated as line + 1) to buf followed by a new line character.
  10. Append the index number to buf followed by a new line character.
  11. Append the offset index number (calculated as index + sourceStartIndex) to buf followed by a new line character.
  12. Try to append a substring of the character array data starting from lastLineIndex with a length of count to buf. If an exception occurs, move to the next step.
  13. If an exception occurs during step 12, try to append a substring of the character array data starting from (index - 10 < 0) ? 0 : index - 10 with a length of index to buf. If this also fails, move to the next step.
  14. If an exception occurs during step 13, append the entire character array data to buf.
  15. Append a number of dots equal to (index - lastLineIndex) to buf.
  16. Append a caret (^) character to buf.
  17. Return the resulting string from buf as the error debug message. sequence diagram

Sources

The Sources class provides utility methods for creating CharSource objects from various input sources, such as strings, byte arrays, files, input streams, and readers. It allows you to easily create CharSource objects from different types of input sources, including strings, byte arrays, files, input streams, and readers. It also provides different methods for creating CharSource objects from specific input types, such as CharSequence, String, byte array, char array, CharBuffer, file, input stream, and Reader. The class handles conversions and error handling for each input type, making it convenient to create CharSource objects for different use cases.

public static CharSource charSeqSource(final CharSequence source)

public static CharSource charSeqSource(final CharSequence source) {
    if (source instanceof String) {
        return new CharArrayCharSource((String) source);
    } else {
        return new CharArrayCharSource(source.toString());
    }
}

The charSeqSource method, defined in the Sources class in the io.nats.jparse.source package, is a public static method that takes a CharSequence parameter named source. The method returns a CharSource object based on the input source.

Here is a step-by-step description of what the charSeqSource method does:

  1. If the source parameter is an instance of the String class:

    • Create a new CharArrayCharSource object, passing in the source parameter (which is casted to a String) as the constructor argument.
    • Return the newly created CharArrayCharSource object.
  2. If the source parameter is not an instance of the String class:

    • Convert the source parameter to a string by invoking the toString() method on it.
    • Create a new CharArrayCharSource object, passing in the converted string as the constructor argument.
    • Return the newly created CharArrayCharSource object.

Note: The CharSource class is not defined in the given code snippet. However, it is assumed to be a class or interface that is imported and accessible within the Sources class. sequence diagram

public static CharSource fileSource(final String fileNameSource, final Charset charset)

public static CharSource fileSource(final String fileNameSource, final Charset charset) {
    try {
        return byteSource(Files.readAllBytes(Paths.get(fileNameSource)), charset);
    } catch (IOException e) {
        throw new IllegalStateException(e);
    }
}

The fileSource method in the io.nats.jparse.source.Sources class is responsible for creating a CharSource object based on the contents of a file specified by the fileNameSource parameter.

Here are the steps performed by the fileSource method:

  1. The method takes two parameters: fileNameSource, which specifies the file name or path, and charset, which specifies the character set to use for reading the file.
  2. Inside a try-catch block, the method calls the static method Files.readAllBytes to read all the bytes from the file specified by fileNameSource. This method returns a byte[] array containing the contents of the file.
  3. The byteSource method is then called, passing the byte[] array and the charset parameter. This method creates and returns a CharSource object based on the provided byte array and character set.
  4. If an IOException occurs during the file reading process, the catch block catches the exception and throws a new IllegalStateException with the caught exception as the cause.

In summary, the fileSource method reads the contents of a file specified by fileNameSource and returns a CharSource object representing the file's content using the specified character set. sequence diagram

public static CharSource fileSource(final File fileSource, final Charset charset)

public static CharSource fileSource(final File fileSource, final Charset charset) {
    try {
        return byteSource(Files.readAllBytes(Paths.get(fileSource.getAbsolutePath())), charset);
    } catch (IOException e) {
        throw new IllegalStateException(e);
    }
}

The method fileSource defined in the class io.nats.jparse.source.Sources is used to create a CharSource from a file. Here is a step-by-step description of what the method does based on its body:

  1. The method takes two parameters: fileSource of type File, which represents the file to read, and charset of type Charset, which specifies the character encoding to use for reading the file.

  2. Inside the method, a try-catch block is used to handle any potential IOException that might occur when reading the file.

  3. The method calls the Files.readAllBytes method, passing in the absolute path of the fileSource file. This method reads all the bytes from the file and returns them as a byte array.

  4. The method then calls another method called byteSource, passing in the byte array obtained from the previous step and the charset provided as arguments. It is not clear from the given code snippet what this byteSource method does, but it is likely used to convert the byte array into a CharSource using the specified character encoding.

  5. If an IOException occurs during the file reading process, the catch block is executed. In this case, an IllegalStateException is thrown, wrapping the original IOException that was caught.

  6. The method ends, either returning the resulting CharSource if the file reading process was successful, or throwing an exception if an error occurred. sequence diagram

public static CharSource readerSource(final Reader readerSource)

public static CharSource readerSource(final Reader readerSource) {
    final BufferedReader reader = new BufferedReader(readerSource);
    StringBuilder stringBuilder = new StringBuilder();
    try {
        String s = reader.readLine();
        while (s != null) {
            stringBuilder.append(s).append('\n');
            s = reader.readLine();
        }
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    } finally {
        try {
            reader.close();
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }
    return new CharArrayCharSource(stringBuilder.toString());
}

The readerSource method in class io.nats.jparse.source.Sources is used to convert a Reader object into a CharSource object. Here is a step-by-step description of what the method does:

  1. The method takes a Reader object as an input parameter named readerSource.

  2. It creates a new BufferedReader object named reader by passing the readerSource to its constructor.

  3. It creates a StringBuilder object named stringBuilder to store the contents of the reader.

  4. The method surrounds the following code block with a try-catch block to handle any exceptions that may occur:

    String s = reader.readLine();
    while (s != null) {
        stringBuilder.append(s).append('\n');
        s = reader.readLine();
    }
    • It initializes a String variable s with the first line read from the reader using the readLine() method.
    • It enters a while loop that continues until s is null.
    • Inside the loop, it appends the value of s to stringBuilder, followed by a newline character '\n'.
    • It reads the next line from reader and assigns it to s.
  5. If any exception occurs during the execution of the code block, an IllegalStateException is thrown, with the caught exception as its cause.

  6. After the try-catch block, a finally block is used to ensure that the reader is properly closed. It is closed by calling the close() method on the reader. If an IOException occurs while closing the reader, an IllegalStateException is thrown, with the caught exception as its cause.

  7. Finally, the method creates a new CharArrayCharSource object by passing the contents of stringBuilder as a String to its constructor.

  8. The method returns the created CharSource object.

This method basically reads the contents of a Reader object line by line, appends each line to a StringBuilder, and converts the resulting string into a CharSource object. sequence diagram

CharArrayCharSource

This class is a char source for char arrays. It is used by the parser to parse strings and is not thread safe. It is not a general-purpose char source.

public static String debugCharDescription(int c)

public static String debugCharDescription(int c) {
    String charString;
    if (c == ' ') {
        charString = "[SPACE]";
    } else if (c == '\t') {
        charString = "[TAB]";
    } else if (c == '\n') {
        charString = "[NEWLINE]";
    } else if (c == ETX) {
        charString = "ETX";
    } else {
        charString = "'" + (char) c + "'";
    }
    charString = charString + " with an int value of " + c;
    return charString;
}

Method Description: debugCharDescription

This method is defined in the io.nats.jparse.source.CharArrayCharSource class. Its purpose is to return a debug description of a given character by converting it to a string representation.

Parameters:

  • c (int): The input character to be debugged.

Return Value:

  • The method returns a string representation of the input character, along with additional debug information.

Step-by-Step Description:

  1. Initialize the variable charString to store the debug description of the character.
  2. Check if the input character c is equal to a space character (' ').
  3. If true, assign "[SPACE]" to charString.
  4. If the character is not a space, check if it is a tab character (' ').
  5. If true, assign "[TAB]" to charString.
  6. If the character is not a tab, check if it is a newline character ('\n').
  7. If true, assign "[NEWLINE]" to charString.
  8. If the character is not a newline, check if it is equal to a specific constant ETX.
  9. If true, assign "ETX" to charString.
  10. If the character does not match any of the previous conditions, it is considered a regular character.
  11. Assign the character surrounded by single quotes (') to charString.
  12. Concatenate the string " with an int value of " and the value of c to charString.
  13. Return the value of charString as the debug description of the character. sequence diagram

@Override

public int next()

@Override
public int next() {
    if (index + 1 >= data.length) {
        index = data.length;
        return ETX;
    }
    return data[++index];
}

The next() method in the io.nats.jparse.source.CharArrayCharSource class is used to retrieve the next character from the source data.

Here is a step-by-step description of what this method does based on its body:

  1. Check if the current index (index) plus 1 is equal to or greater than the length of the data array.
  2. If the condition is true, it means that there are no more characters to read from the source data. 2.1. Set the index to the length of the data array to indicate that we have reached the end. 2.2. Return the ETX constant, which represents the end-of-transmission character.
  3. If the condition in step 1 is false, it means that there are more characters to read from the source data. 3.1. Increment the index by 1. 3.2. Return the character at the new index in the data array.

This method basically keeps track of the current position in the data array and returns the next character each time it is called. If there are no more characters to read, it returns the ETX constant to indicate the end of transmission. sequence diagram

@Override

public void checkForJunk()

@Override
public void checkForJunk() {
    int index = this.index;
    final char[] data = this.data;
    final int length = data.length;
    int ch = ETX;
    for (; index < length; index++) {
        ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                throw new UnexpectedCharacterException("Junk", "Unexpected extra characters", this);
        }
    }
}

The checkForJunk method, defined in the CharArrayCharSource class, is used to check if there are any unexpected extra characters in the data stored in the CharArrayCharSource object.

Here is a step-by-step description of what the method does based on its body:

  1. It begins by initializing the index variable with the current index of the character being checked in the data.
  2. It then retrieves the data stored in the CharArrayCharSource object and assigns it to the data variable.
  3. The length of the data is obtained and stored in the length variable.
  4. The ch variable is initialized with the ETX (End of Text) character. ETX typically has a value of 3.
  5. A loop is initiated where index is incremented for every iteration until it reaches the length of the data.
  6. Inside the loop, the character at the current index in the data is assigned to the ch variable.
  7. The switch statement is used to perform different actions based on the value of ch.
  8. If ch matches any of the four white space characters - NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, or SPACE_WS, the loop continues to the next iteration without executing any further code.
  9. If ch does not match any of the white space characters, it means that an unexpected character is found.
  10. In such a case, an UnexpectedCharacterException is thrown with the message "Junk" and "Unexpected extra characters", along with the current CharArrayCharSource object as an argument.
  11. If the loop completes without throwing an exception, it means that there are no unexpected extra characters in the data. sequence diagram

@Override

public int nextSkipWhiteSpace()

@Override
public int nextSkipWhiteSpace() {
    int index = this.index + 1;
    final char[] data = this.data;
    final int length = data.length;
    int ch = ETX;
    loop: for (; index < length; index++) {
        ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                break loop;
        }
    }
    this.index = index;
    return index == length ? ETX : ch;
}

The method nextSkipWhiteSpace is defined in the class io.nats.jparse.source.CharArrayCharSource. Here is a step-by-step description of what this method does based on its body:

  1. It overrides the method nextSkipWhiteSpace from the superclass.

  2. It initializes a variable index with the value of this.index + 1.

  3. It retrieves the character array data and its length from the class.

  4. It initializes a variable ch with the value of ETX (end-of-text character).

  5. It starts a loop that iterates over the characters in the data array, starting from the index value.

  6. Inside the loop, it assigns the current character to the variable ch.

  7. It uses a switch statement to check the value of ch against four possible whitespace characters: NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, and SPACE_WS.

  8. If ch matches any of the whitespace characters, the loop continues to the next iteration without executing the remaining code in the loop body.

  9. If ch does not match any of the whitespace characters, the loop is exited using the break statement with the loop label.

  10. After the loop, the variable index is assigned the value of the loop index.

  11. The method then returns the value of ch, unless index is equals to length, in which case it returns the value of ETX.

Please note that the values ETX, NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, and SPACE_WS are not defined in the given code snippet and their meanings may be specific to the context of the code. sequence diagram

@Override

public char skipWhiteSpace()

@Override
public char skipWhiteSpace() {
    int index = this.index;
    final char[] data = this.data;
    final int length = data.length;
    char ch;
    loop: for (; index < length; index++) {
        ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                break loop;
        }
    }
    this.index = index;
    return data[index];
}

The skipWhiteSpace method in the CharArrayCharSource class is used to skip any white space characters (including new lines, carriage returns, tabs, and spaces) in the character array data.

Here is a step-by-step description of what the method does:

  1. It starts by getting the current index from the this.index variable and assigning it to a local variable index.
  2. It also assigns the character array data from the this.data variable to a local variable data.
  3. It gets the length of the character array and assigns it to a local variable length.
  4. It declares a local variable ch to hold the current character.
  5. It starts a loop that iterates over the character array from the current index index up to the length of the character array length.
  6. Inside the loop, it assigns the current character at the current index index to the variable ch.
  7. It uses a switch statement to check if the ch is a white space character (defined as NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, or SPACE_WS).
  8. If the ch is a white space character, it continues to the next iteration of the loop.
  9. If the ch is not a white space character, it breaks the loop using a break loop statement.
  10. After the loop finishes, it updates the index this.index to the value of the local variable index.
  11. Finally, it returns the character ch found at the index index in the character array data.

In summary, the skipWhiteSpace method iterates over a character array, starting from the current index, and skips any white space characters until it finds a non-white space character. It then updates the index and returns the non-white space character found. sequence diagram

@Override

public String toEncodedStringIfNeeded(int start, int end)

@Override
public String toEncodedStringIfNeeded(int start, int end) {
    if (CharArrayUtils.hasEscapeChar(data, start, end)) {
        return getEncodedString(start, end);
    } else {
        return this.getString(start, end);
    }
}

The toEncodedStringIfNeeded method defined in the CharArrayCharSource class in the io.nats.jparse.source package is responsible for converting a portion of the character array to a string, checking if any escape characters exist within the range.

Here is a step-by-step description of what the method does based on its body:

  1. The method overrides the toEncodedStringIfNeeded method from its parent class.
  2. It takes two parameters, start and end, which represent the start and end indices of the desired portion of the character array to convert.
  3. The method starts by checking whether the character array within the specified range contains any escape characters using the CharArrayUtils.hasEscapeChar method.
  4. If any escape characters are found, it invokes the getEncodedString method with the same start and end indices to return the properly encoded string.
  5. If no escape characters are found within the specified range, it invokes the getString method with the same start and end indices to return the string as it is without any encoding.
  6. The method then returns the result of either the encoded or raw string based on the presence of escape characters within the specified range. sequence diagram

@Override

public NumberParseResult findEndOfNumberFast()

@Override
public NumberParseResult findEndOfNumberFast() {
    int i = index + 1;
    char ch = 0;
    final char[] data = this.data;
    final int length = data.length;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i, false);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case DECIMAL_POINT:
                index = i;
                return findEndOfFloatFast();
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponentFast();
            default:
                throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
        }
    }
    index = i;
    return new NumberParseResult(i, false);
}

Method: findEndOfNumberFast

This method is defined in the class io.nats.jparse.source.CharArrayCharSource and is used to find the end of a number in a character array.

Step 1:

Initialize the variable i to index + 1.

Step 2:

Initialize the variable ch to 0.

Step 3:

Get a reference to the character array data from this.data.

Step 4:

Get the length of the character array and store it in the variable length.

Step 5:

Start a for loop, iterating from i to length.

Step 6:

Inside the loop, get the character at index i and store it in the variable ch.

Step 7:

Use a switch statement to check for various characters:

  • If ch is a whitespace character (e.g. newline, carriage return, tab, space) or one of the specified tokens (ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, ARRAY_END_TOKEN), update the value of index to i and return a new NumberParseResult with the updated index and false as the boolean value.
  • If ch is any of the digits (NUM_0, NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9), continue to the next iteration.
  • If ch is a decimal point (DECIMAL_POINT), update the value of index to i and return the result of calling the method findEndOfFloatFast().
  • If ch is an exponent marker (EXPONENT_MARKER or EXPONENT_MARKER2), update the value of index to i and return the result of calling the method parseFloatWithExponentFast().
  • If none of the above conditions match, throw an IllegalStateException with the message "Unexpected character" followed by ch and the current value of index.

Step 8:

After the loop ends, update the value of index to i.

Step 9:

Finally, return a new NumberParseResult with i as the index and false as the boolean value. sequence diagram

private NumberParseResult findEndOfFloatFast()

private NumberParseResult findEndOfFloatFast() {
    int i = index + 1;
    char ch = 0;
    final char[] data = this.data;
    final int length = data.length;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i, true);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponentFast();
            default:
                throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
        }
    }
    index = i;
    return new NumberParseResult(i, true);
}

The method findEndOfFloatFast in class io.nats.jparse.source.CharArrayCharSource is used to find the end of a floating-point number in a character array. It returns a NumberParseResult object which contains the position of the end of the floating-point number and a flag indicating if the parsing was successful.

Here is a step-by-step description of what the method does:

  1. Initialize a local variable i to index + 1, where index is an instance variable representing the current position in the character array.
  2. Initialize a local variable ch to 0.
  3. Get a reference to the character array data from the this object, which refers to the current instance of CharArrayCharSource.
  4. Get the length of the character array and store it in a local variable length.
  5. Start a for loop, iterating over the characters in the character array starting from i and going up to length - 1.
  6. Inside the loop, get the current character at index i and store it in the variable ch.
  7. Use a switch statement to check the value of ch against various cases:
    • If ch is equal to any of the whitespace characters (NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS) or any of the JSON delimiters (ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, ARRAY_END_TOKEN), then update the index variable to i and return a new NumberParseResult object with the current position i and true as the flag.
    • If ch is any of the digit characters (NUM_0 to NUM_9), continue to the next iteration of the loop.
    • If ch is either the exponent marker character (EXPONENT_MARKER) or the second exponent marker character (EXPONENT_MARKER2), update the index variable to i and return the result of calling the parseFloatWithExponentFast method.
    • If none of the above cases match, throw an UnexpectedCharacterException with the message "Parsing JSON Float Number", "Unexpected character", the current instance of CharArrayCharSource, the unexpected character ch, and the current position i.
  8. After the for loop finishes, update the index variable to i and return a new NumberParseResult object with the current position i and true as the flag. sequence diagram

private NumberParseResult parseFloatWithExponentFast()

private NumberParseResult parseFloatWithExponentFast() {
    int i = index + 1;
    char ch = 0;
    int signOperator = 0;
    final char[] data = this.data;
    final int length = data.length;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i, true);
            case MINUS:
            case PLUS:
                signOperator++;
                if (signOperator > 1) {
                    throw new IllegalStateException("Too many sign operators when parsing exponent of float");
                }
                break;
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            default:
                throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
        }
    }
    index = i;
    return new NumberParseResult(i, true);
}

The method parseFloatWithExponentFast is defined in the class io.nats.jparse.source.CharArrayCharSource and returns a NumberParseResult.

Here is a step by step description of what the method is doing:

  1. Initialize the variable i with the value index + 1.
  2. Initialize the variable ch with the value 0.
  3. Initialize the variable signOperator with the value 0.
  4. Get the character array data from the object this and assign it to the variable data.
  5. Get the length of the character array data and assign it to the variable length.
  6. Start a loop that iterates from the value of i to the length of data.
    • Assign the current character of data at index i to the variable ch.
    • Use a switch statement to check the value of ch against various cases:
      • If ch is equal to any of the following characters: NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, or ARRAY_END_TOKEN, set index to i and return a new NumberParseResult object with the value of i and true.
      • If ch is equal to MINUS or PLUS, increment signOperator by 1. If signOperator is greater than 1, throw an IllegalStateException with the message "Too many sign operators when parsing exponent of float".
      • If ch is any of the digits from NUM_0 to NUM_9, continue to the next iteration.
      • If none of the above cases match, throw an IllegalStateException with the message "Unexpected character" followed by the value of ch and "at index" followed by the value of index.
  7. After the loop ends, set index to i and return a new NumberParseResult object with the value of i and true. sequence diagram

@Override

public int findEndOfEncodedStringFast()

@Override
public int findEndOfEncodedStringFast() {
    int i = ++index;
    final char[] data = this.data;
    final int length = data.length;
    boolean controlChar = false;
    for (; i < length; i++) {
        char ch = data[i];
        switch(ch) {
            case CONTROL_ESCAPE_TOKEN:
                controlChar = !controlChar;
                continue;
            case STRING_END_TOKEN:
                if (!controlChar) {
                    index = i + 1;
                    return i;
                }
                controlChar = false;
                break;
            default:
                controlChar = false;
                break;
        }
    }
    throw new IllegalStateException("Unable to find closing for String");
}

The findEndOfEncodedStringFast method in the io.nats.jparse.source.CharArrayCharSource class is used to find the index of the closing delimiter of an encoded string. Here is a step-by-step description of what this method does:

  1. Initialize i with the incremented index value. This will be the starting index for searching the encoding string.
  2. Get the character array data from the source object.
  3. Get the length of the character array.
  4. Initialize a boolean variable controlChar to false. This variable is used to keep track of whether a control character was encountered.
  5. Start a loop from i to length - 1. This loop iterates over each character in the character array.
  6. Get the character ch at index i.
  7. Check the value of ch using a switch statement to handle different cases:
    • If ch is equal to the CONTROL_ESCAPE_TOKEN, toggle the value of controlChar (i.e., change it from true to false or vice versa).
    • If ch is equal to the STRING_END_TOKEN and controlChar is false, update the index to i + 1 and return i. This denotes that the end of the encoding string has been found.
    • If ch is anything else, set controlChar to false.
  8. If no end of the encoding string is found, throw an IllegalStateException with the message "Unable to find closing for String".

Overall, this method iterates over the characters in the input character array starting from the given index and looks for the closing delimiter of an encoded string. It handles control characters and ensures that the closing delimiter is not escaped before returning the index of the closing delimiter. If the closing delimiter is not found, it throws an exception to indicate the error. sequence diagram

private int findEndOfStringControlEncode(int i)

private int findEndOfStringControlEncode(int i) {
    final char[] data = this.data;
    final int length = data.length;
    char ch = 0;
    ch = data[i];
    switch(ch) {
        case CONTROL_ESCAPE_TOKEN:
        case STRING_END_TOKEN:
        case 'n':
        case 'b':
        case '/':
        case 'r':
        case 't':
        case 'f':
            return i;
        case 'u':
            return findEndOfHexEncoding(i);
        default:
            throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
    }
}

Method: findEndOfStringControlEncode in io.nats.jparse.source.CharArrayCharSource

This method is used to find the index of the closing character for a JSON string when the starting character is a control or escape character.

Parameters:

  • i: Index of the starting character in the data array.

Steps:

  1. Get the reference to the data array and the length of the array.
  2. Initialize a char variable ch to 0.
  3. Assign the value of the character at index i in the data array to the ch variable.
  4. Perform a switch-case check on the value of ch:
    • If ch is equal to CONTROL_ESCAPE_TOKEN, STRING_END_TOKEN, 'n', 'b', '/', 'r', 't', or 'f', return the current index i.
    • If ch is equal to 'u', call the findEndOfHexEncoding method and return its result.
    • If ch does not match any of the above cases, throw an UnexpectedCharacterException with appropriate error message, indicating an unexpected character while finding the closing character for the JSON string.

Return:

  • The index of the closing character for the JSON string.

Note: The actual values for CONTROL_ESCAPE_TOKEN and STRING_END_TOKEN are not provided in the given code snippet sequence diagram

@Override

public int findEndOfEncodedString()

@Override
public int findEndOfEncodedString() {
    int i = ++index;
    final char[] data = this.data;
    final int length = data.length;
    char ch = 0;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case CONTROL_ESCAPE_TOKEN:
                i = findEndOfStringControlEncode(i + 1);
                continue;
            case STRING_END_TOKEN:
                index = i + 1;
                return i;
            default:
                if (ch >= SPACE_WS) {
                    continue;
                }
                throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
        }
    }
    throw new UnexpectedCharacterException("Parsing JSON Encoded String", "Unable to find closing for String", this, ch, i);
}

The findEndOfEncodedString method is defined in the io.nats.jparse.source.CharArrayCharSource class. It overrides the findEndOfEncodedString method from its parent class.

Here is a step-by-step description of what the method is doing:

  1. The index variable is incremented by 1 and stored in the i variable.
  2. The data char array from the parent class is assigned to the data variable.
  3. The length of the data array is stored in the length variable.
  4. A variable ch is initialized to the value 0.
  5. A for loop is started, iterating from i to length.
  6. In each iteration, the value at the current index i in the data array is stored in the ch variable.
  7. A switch statement is used to check the value of ch.
  8. If ch is equal to CONTROL_ESCAPE_TOKEN, then the findEndOfStringControlEncode method is called with the argument i + 1. The returned value is then assigned back to i, and the next iteration of the loop is started.
  9. If ch is equal to STRING_END_TOKEN, then index is updated to i + 1, and the current value of i is returned.
  10. If ch is none of the above, it checks if ch is greater than or equal to SPACE_WS.
    • If it is, the loop continues to the next iteration.
    • If it is not, an UnexpectedCharacterException is thrown with a message stating the unexpected character, the current CharSource, ch, and the index i.
  11. If the loop completes without finding a closing for a string, an UnexpectedCharacterException is thrown with a message stating the inability to find a closing for the string, the current CharSource, the last value of ch, and the last value of i.

This method is used to find the end of an encoded string in the JSON input. It iterates through the characters starting from the index position and looks for the closing token of the string or any control escape tokens. If a closing token is found, it updates the index and returns the position of the closing token. If a control escape token is found, it delegates the further handling to the findEndOfStringControlEncode method. If none of these conditions are met, it throws an exception indicating an unexpected character. If the loop completes without finding a closing token, it throws an exception indicating the inability to find a closing for the string. sequence diagram

private int findEndOfHexEncoding(int index)

private int findEndOfHexEncoding(int index) {
    final char[] data = this.data;
    final int length = data.length;
    if (isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index])) {
        return index;
    } else {
        throw new UnexpectedCharacterException("Parsing hex encoding in a string", "Unexpected character", this);
    }
}

The method findEndOfHexEncoding in the class io.nats.jparse.source.CharArrayCharSource is used to find the end of a hex encoding in a string. Here is a step-by-step description of what the method is doing:

  1. It takes an input parameter index which represents the current position in the character array.

  2. It initializes a local variable data with the character array this.data and length with the length of the character array.

  3. It checks if the character at position index + 1, index + 2, index + 3, and index + 4 in the data array are valid hexadecimal characters by calling the method isHex().

  4. If all four characters are valid hex characters, the method returns the current index value.

  5. If any of the characters is not a valid hex character, the method throws an exception of type UnexpectedCharacterException with the error message "Unexpected character" and a reference to the this object.

In summary, the findEndOfHexEncoding method iterates over the characters in the data array starting from the index position and checks if the next four characters form a valid hex encoding. If they do, it returns the index of the last character in the encoding. If any of the characters is not valid, it throws an exception. sequence diagram

private boolean isHex(char datum)

private boolean isHex(char datum) {
    switch(datum) {
        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F':
        case 'a':
        case 'b':
        case 'c':
        case 'd':
        case 'e':
        case 'f':
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            return true;
        default:
            return false;
    }
}

The method isHex in the class io.nats.jparse.source.CharArrayCharSource is used to check if a given character is a hex digit.

Here is the step-by-step description of what the method is doing based on its body:

  1. Define a private boolean method named isHex that takes a character as input.
  2. The method uses a switch-case statement to handle different cases of the datum character.
  3. In the switch statement, each case represents a valid hex digit character. The valid hex digit characters are: 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', and '9'.
  4. If the datum character matches any of the valid hex digit characters, the method returns true.
  5. If the datum character does not match any of the valid hex digit characters, the method returns false.
  6. The method is private, which means it can only be accessed within the io.nats.jparse.source.CharArrayCharSource class.

That's the step-by-step description of the isHex method. It checks whether a given character is a valid hex digit character. sequence diagram

@Override

public int findAttributeEnd()

@Override
public int findAttributeEnd() {
    int index = this.index;
    final char[] data = this.data;
    final int length = this.data.length;
    loop: for (; index < length; index++) {
        char ch = data[index];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
                this.index = index;
                break loop;
        }
    }
    return index;
}

The method findAttributeEnd in the class io.nats.jparse.source.CharArrayCharSource is used to find the end of an attribute within a character array.

Here are the steps performed by this method:

  1. The method overrides the findAttributeEnd method, ensuring that it has the same signature as the overridden method in the parent class.

  2. The method first initializes a local variable index with the value of this.index. this.index refers to the current index within the character array.

  3. The method then assigns the character array data from the class instance to a local variable data.

  4. It also assigns the length of the character array data to a local variable length.

  5. The method has a loop that iterates from the current index index to the length of the character array data.

  6. Inside the loop, it retrieves the character ch at the current index index from the character array data.

  7. It then checks the character ch against several predefined whitespace characters, like NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, and ATTRIBUTE_SEP.

  8. If the character ch matches any of these whitespace characters, it updates the this.index to the current index index and breaks the loop using a labeled break statement.

  9. After the loop ends, the method returns the value of index.

To summarize, the findAttributeEnd method scans through the character array data starting from the current index this.index until it finds a whitespace character. It then returns the index where the whitespace character was found, indicating the end of the attribute. sequence diagram

@Override

public boolean findChar(char c)

@Override
public boolean findChar(char c) {
    int index = this.index;
    final char[] data = this.data;
    final int length = this.data.length;
    for (; index < length; index++) {
        if (data[index] == c) {
            this.index = index;
            return true;
        }
    }
    return false;
}

The findChar method in the CharArrayCharSource class is used to find a specific character in a character array.

Here is a step-by-step description of what the method is doing:

  1. The method overrides the findChar method declared in the superinterface or superclass.

  2. The this.index variable is assigned to a local variable called index. This is done for efficiency purposes as retrieving the instance variable directly multiple times may be costly.

  3. The this.data variable, which represents the character array being searched, is assigned to a local variable called data.

  4. The length variable is assigned the length of the data character array.

  5. A for loop is started with index being the starting point of the loop and length being the end condition.

  6. Inside the loop, the current character at the index position of the data array is compared to the character c that is being searched for.

  7. If the characters match, the this.index instance variable is updated with the current index value, and the method returns true indicating that the character was found.

  8. If the loop completes without finding a matching character, the method returns false indicating that the character was not found in the array.

Please note that this step-by-step description assumes that the instance variables (this.index, this.data, etc.) are properly initialized before using the findChar method. sequence diagram

@Override

public int findEndString()

@Override
public int findEndString() {
    int i = ++index;
    final char[] data = this.data;
    final int length = data.length;
    char ch = 0;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case STRING_END_TOKEN:
                index = i;
                return i;
            default:
                if (ch >= SPACE_WS) {
                    continue;
                }
                throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
        }
    }
    throw new UnexpectedCharacterException("Parsing JSON String", "Unable to find closing for String", this, ch, i);
}

The findEndString method in the CharArrayCharSource class is used to find the end of a JSON string within a given character array.

Here is a step-by-step description of what the method is doing:

  1. Increment the index by 1 and assign it to a local variable i.
  2. Retrieve the character array data from the current CharArrayCharSource object.
  3. Get the length of the character array and assign it to a local variable length.
  4. Initialize a variable ch with a value of 0.
  5. Start a loop from the current index (i) until the end of the character array.
  6. Within the loop, retrieve the character at position i from the character array and assign it to ch.
  7. Use a switch statement to check the value of ch.
    • If ch is equal to a constant variable STRING_END_TOKEN, update the index with the current value of i and return i as the index of the end of the string.
    • If ch is not equal to STRING_END_TOKEN, check if ch is greater than or equal to a constant variable SPACE_WS (a whitespace character).
      • If it is greater than or equal to SPACE_WS, continue to the next iteration of the loop.
      • If it is not greater than or equal to SPACE_WS, throw an UnexpectedCharacterException with a message indicating that an unexpected character was found while finding the closing for the string.
  8. If the end of the character array is reached without finding the closing for the string, throw an UnexpectedCharacterException with a message indicating that the closing for the string was not found.

In summary, this method iterates over the character array starting from the current index, looking for the end of a JSON string. If the end of the string is found, the method returns the index of the closing character. If an unexpected character is encountered, an exception is thrown. If the closing for the string is not found, an exception is also thrown. sequence diagram

@Override

public NumberParseResult findEndOfNumber()

@Override
public NumberParseResult findEndOfNumber() {
    final char startCh = getCurrentChar();
    final int startIndex = index;
    char ch = startCh;
    int i = index + 1;
    final char[] data = this.data;
    final int length = data.length;
    loop: for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                break loop;
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case DECIMAL_POINT:
                if (startCh == MINUS) {
                    final int numLenSoFar = i - startIndex;
                    if (numLenSoFar == 1) {
                        throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
                    }
                }
                index = i;
                return findEndOfFloat();
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponent();
            default:
                throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
        }
    }
    index = i;
    final int numLength = i - startIndex;
    switch(startCh) {
        case NUM_0:
            if (numLength != 1) {
                throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a 0 ", this, startCh, startIndex);
            }
            break;
        case PLUS:
            throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a plus ", this, startCh, startIndex);
        case MINUS:
            switch(numLength) {
                case 1:
                    throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't be only a minus, number is missing", this, startCh, startIndex);
                case 2:
                    break;
                default:
                    if (data[startIndex + 1] == NUM_0) {
                        throw new UnexpectedCharacterException("Parsing JSON Int Number", "0 can't be after minus sign", this, startCh, startIndex);
                    }
            }
    }
    return new NumberParseResult(i, false);
}

The findEndOfNumber method is defined in the io.nats.jparse.source.CharArrayCharSource class. This method is used to find the end index of a number in a character array source.

Here is a step-by-step description of what the method is doing:

  1. It starts by getting the current character from the character array source (getCurrentChar()).
  2. It initializes the startCh variable with the current character and the startIndex variable with the current index.
  3. It then enters a loop starting from i = index + 1 until i < length (where length is the length of the character array).
  4. Inside the loop, it assigns the next character (data[i]) to the ch variable.
  5. It then performs a switch case on the ch variable to check for various characters and perform different actions:
    • If the character is one of the whitespace characters (NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS), one of the separators (ATTRIBUTE_SEP, ARRAY_SEP), or one of the end tokens (OBJECT_END_TOKEN, ARRAY_END_TOKEN), it breaks out of the loop.
    • If the character is one of the digits (NUM_0 to NUM_9), it continues to the next iteration of the loop.
    • If the character is a decimal point (DECIMAL_POINT), it checks if the startCh is a minus sign (MINUS). If it is, it throws an exception if the length of the number so far is 1. It then sets the index to i and returns the result of calling the findEndOfFloat method.
    • If the character is an exponent marker (EXPONENT_MARKER or EXPONENT_MARKER2), it sets the index to i and returns the result of calling the parseFloatWithExponent method.
    • If none of the above cases match, it throws an exception for an unexpected character.
  6. After the loop, it sets the index to i (the current index) and calculates the length of the number (numLength) by subtracting the startIndex from i.
  7. It then performs a switch case on the startCh variable to check for different cases:
    • If the startCh is NUM_0 and the length of the number is not 1, it throws an exception for an integer number starting with 0.
    • If the startCh is a plus sign (PLUS), it throws an exception for an integer number starting with a plus sign.
    • If the startCh is a minus sign (MINUS), it checks the length of the number:
      • If the length is 1, it throws an exception for a minus sign without a number.
      • If the length is 2, it continues to the next step.
      • If the length is greater than 2 and the character after the minus sign is NUM_0, it throws an exception for 0 being after a minus sign.
  8. Finally, it returns a new NumberParseResult object with the end index (i) and a boolean indicating whether the number is a float (false). sequence diagram

private NumberParseResult findEndOfFloat()

private NumberParseResult findEndOfFloat() {
    int i = index + 1;
    char ch = (char) next();
    if (!isNumber(ch)) {
        throw new UnexpectedCharacterException("Parsing float part of number", "After decimal point expecting number but got", this, ch, this.index);
    }
    final char[] data = this.data;
    final int length = data.length;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i, true);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            case EXPONENT_MARKER:
            case EXPONENT_MARKER2:
                index = i;
                return parseFloatWithExponent();
            default:
                throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
        }
    }
    index = i;
    return new NumberParseResult(i, true);
}

The findEndOfFloat method is a private method defined in the io.nats.jparse.source.CharArrayCharSource class. It is responsible for finding the end of a floating-point number within a JSON string.

Here is a step-by-step description of what the method does based on its body:

  1. The method starts by initializing a local variable i with the value of index + 1.

  2. It then retrieves the next character ch from the input stream by calling the next() method.

  3. It checks if ch is a valid number character by calling the isNumber() method. If it is not a valid number character, it throws an UnexpectedCharacterException with an appropriate error message.

  4. Next, the method accesses the data array and length of the array from the parent object.

  5. It enters a for loop that iterates from i to length-1.

  6. Inside the loop, it gets the character ch at the current index i from the data array.

  7. It then performs a switch statement on ch to handle different types of characters:

    • If ch is one of the whitespace characters or special tokens (e.g., newline, tab, comma, array or object end token), it sets the index to i and returns a new NumberParseResult object with the current index and true value indicating that the float number has been successfully parsed.

    • If ch is one of the numeric digits (0-9), it continues the loop without performing any action.

    • If ch is an exponent marker (e.g., 'E' or 'e'), it sets the index to i and calls the parseFloatWithExponent method to handle parsing of the floating-point number with an exponent.

    • If ch is any other character, it throws an UnexpectedCharacterException with an appropriate error message.

  8. After the loop, it sets the index to i and returns a new NumberParseResult object with the current index and true value indicating that the float number has been successfully parsed.

In summary, the findEndOfFloat method iterates through the characters of the input string starting from the index + 1 position. It checks each character to determine if it is a valid part of a floating-point number, until it reaches a character that is not part of the number. It returns the index of the last character of the number and whether or not the number was successfully parsed. sequence diagram

private boolean isNumber(final char ch)

private boolean isNumber(final char ch) {
    switch(ch) {
        case NUM_0:
        case NUM_1:
        case NUM_2:
        case NUM_3:
        case NUM_4:
        case NUM_5:
        case NUM_6:
        case NUM_7:
        case NUM_8:
        case NUM_9:
            return true;
        default:
            return false;
    }
}

Method Description: isNumber

Class: io.nats.jparse.source.CharArrayCharSource

The isNumber method is defined within the io.nats.jparse.source.CharArrayCharSource class. It determines whether a given character is a number or not.

Parameter: ch

  • Type: char
  • Description: The character that needs to be checked.

Steps:

  1. The method takes a character ch as input.
  2. It uses a switch statement to compare the input character with a set of predefined constants representing the digits 0 to 9.
  3. If the input character matches any of the predefined constants, the method returns true, indicating that the character is a number.
  4. If the input character does not match any of the predefined constants, the method returns false, indicating that the character is not a number. sequence diagram

private NumberParseResult parseFloatWithExponent()

private NumberParseResult parseFloatWithExponent() {
    char ch = (char) next();
    if (!isNumberOrSign(ch)) {
        throw new UnexpectedCharacterException("Parsing exponent part of float", "After exponent expecting number or sign but got", this, ch, this.index);
    }
    if (isSign(ch)) {
        ch = (char) next();
        if (!isNumber(ch)) {
            throw new UnexpectedCharacterException("Parsing exponent part of float after sign", "After sign expecting number but got", this, ch, this.index);
        }
    }
    int i = index + 1;
    final char[] data = this.data;
    final int length = data.length;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
            case ATTRIBUTE_SEP:
            case ARRAY_SEP:
            case OBJECT_END_TOKEN:
            case ARRAY_END_TOKEN:
                index = i;
                return new NumberParseResult(i, true);
            case NUM_0:
            case NUM_1:
            case NUM_2:
            case NUM_3:
            case NUM_4:
            case NUM_5:
            case NUM_6:
            case NUM_7:
            case NUM_8:
            case NUM_9:
                break;
            default:
                throw new UnexpectedCharacterException("Parsing Float with exponent", "Unable to find closing for Number", this, ch, i);
        }
    }
    index = i;
    return new NumberParseResult(i, true);
}

The method parseFloatWithExponent() in class io.nats.jparse.source.CharArrayCharSource is used to parse a floating-point number with an exponent.

Here is a step-by-step description of what the method does based on its body:

  1. It retrieves the next character from the input and assigns it to the variable ch.
  2. It checks if the character ch is a number or a sign. If it is not, it throws an UnexpectedCharacterException with an error message indicating that it was expecting a number or sign.
  3. If the character ch is a sign, it retrieves the next character from the input and assigns it to ch. Then, it checks if ch is a number. If it is not, it throws an UnexpectedCharacterException with an error message indicating that it was expecting a number after the sign.
  4. It initializes an integer variable i with index + 1. This will be used to iterate through the characters in the data array.
  5. It retrieves the data array and its length and assigns them to data and length variables respectively.
  6. It enters a loop that starts at i and iterates until i reaches the end of the data array.
  7. Inside the loop, it assigns the current character at index i to ch.
  8. It then checks the value of ch against a set of characters representing whitespace, separators, and the end of objects/arrays. If a match is found, it updates the value of index to i and returns a new NumberParseResult object with the current index and a flag indicating successful parsing.
  9. If ch is a digit (0-9), it continues to the next iteration of the loop.
  10. If ch does not match any of the previous cases, it throws an UnexpectedCharacterException with an error message indicating that it was unable to find a closing character for the number.
  11. After the loop ends, it updates the value of index to i and returns a new NumberParseResult object with the current index and a flag indicating successful parsing. sequence diagram

private boolean isNumberOrSign(char ch)

private boolean isNumberOrSign(char ch) {
    switch(ch) {
        case NUM_0:
        case NUM_1:
        case NUM_2:
        case NUM_3:
        case NUM_4:
        case NUM_5:
        case NUM_6:
        case NUM_7:
        case NUM_8:
        case NUM_9:
        case MINUS:
        case PLUS:
            return true;
        default:
            return false;
    }
}

Method: isNumberOrSign

This method is defined in the io.nats.jparse.source.CharArrayCharSource class and is used to determine if a given character is either a number or a sign (+ or -).

Algorithm:

  1. Accept a character ch as input.
  2. Perform a switch case on the character ch.
  3. Check if ch matches any of the following cases:
    • If ch is equal to the character constant NUM_0
    • If ch is equal to the character constant NUM_1
    • If ch is equal to the character constant NUM_2
    • If ch is equal to the character constant NUM_3
    • If ch is equal to the character constant NUM_4
    • If ch is equal to the character constant NUM_5
    • If ch is equal to the character constant NUM_6
    • If ch is equal to the character constant NUM_7
    • If ch is equal to the character constant NUM_8
    • If ch is equal to the character constant NUM_9
    • If ch is equal to the character constant MINUS
    • If ch is equal to the character constant PLUS
  4. If ch matches any of the above cases, return true.
  5. If ch does not match any of the above cases, return false. sequence diagram

private boolean isSign(char ch)

private boolean isSign(char ch) {
    switch(ch) {
        case MINUS:
        case PLUS:
            return true;
        default:
            return false;
    }
}

The isSign method in the CharArrayCharSource class is used to determine if a given character is a sign symbol.

Here is a step-by-step description of what the method does:

  1. The method takes a single character (ch) as input.
  2. It uses a switch statement to check the value of ch.
  3. If the value of ch is equal to the constant MINUS, which represents a minus sign, or the constant PLUS, which represents a plus sign, it returns true.
  4. If the value of ch does not match any of the cases in the switch statement, it returns false.

In summary, the isSign method checks if a given character is a sign symbol (minus or plus) and returns true if it is or false if it isn't. sequence diagram

@Override

public int findFalseEnd()

@Override
public int findFalseEnd() {
    if (this.data[++index] == 'a' && this.data[++index] == 'l' && this.data[++index] == 's' && this.data[++index] == 'e') {
        return ++index;
    } else {
        throw new UnexpectedCharacterException("Parsing JSON False Boolean", "Unexpected character", this);
    }
}

The findFalseEnd method defined in the CharArrayCharSource class, located at io.nats.jparse.source.CharArrayCharSource, performs the following steps:

  1. The method overrides the findFalseEnd method, which is declared in a superclass.
  2. It starts by checking if the character at the next index (++index) in the data array is equal to the character 'a'.
  3. If the above condition is true, it also checks if the character at the next index is 'l', 's', and 'e' respectively.
  4. If all the characters 'a', 'l', 's', and 'e' are found consecutively, it returns the incremented index value.
  5. If any of the characters are not found consecutively, it throws an UnexpectedCharacterException.
  6. The UnexpectedCharacterException takes the following parameters: "Parsing JSON False Boolean" as the error message, "Unexpected character" as the detailed error description, and the current CharArrayCharSource instance (this) where the exception occurred.

Please note that the ++index operator increments the index value and returns the incremented value. sequence diagram

@Override

public int findTrueEnd()

@Override
public int findTrueEnd() {
    if (this.data[++index] == 'r' && this.data[++index] == 'u' && this.data[++index] == 'e') {
        return ++index;
    } else {
        throw new UnexpectedCharacterException("Parsing JSON True Boolean", "Unexpected character", this);
    }
}

The findTrueEnd method in the io.nats.jparse.source.CharArrayCharSource class is used to determine the end position of the "true" boolean value in a JSON document.

Here is a step-by-step breakdown of how the method works:

  1. The method overrides the findTrueEnd method defined in the superclass.
  2. The method begins by incrementing the index variable using the ++index syntax.
  3. It then checks if the character at the current index in the data array is equal to the character 'r'.
  4. If it is, the method proceeds to the next step.
  5. The method then increments the index variable again and checks if the character at the new index is equal to the character 'u'.
  6. If it is, the method proceeds to the next step.
  7. The method increments the index variable once more and checks if the character at the new index is equal to the character 'e'.
  8. If it is, the method increments the index again and returns the new index value.
  9. If any of the checks made in steps 3, 5, or 7 fail, it means that there is an unexpected character in the input, and the method throws an UnexpectedCharacterException.
  10. The UnexpectedCharacterException is constructed with a message indicating that it occurred while parsing a JSON True Boolean and providing the information about the unexpected character and the current source.
  11. The exception is thrown, and the execution of the method is stopped.

This findTrueEnd method allows the caller to locate the true boolean value in a JSON document and determine its end position. sequence diagram

@Override

public boolean findObjectEndOrAttributeSep()

@Override
public boolean findObjectEndOrAttributeSep() {
    int i = index;
    char ch = 0;
    final char[] data = this.data;
    final int length = data.length;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case OBJECT_END_TOKEN:
                this.index = i + 1;
                return true;
            case ATTRIBUTE_SEP:
                this.index = i;
                return false;
        }
    }
    throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this);
}

The method findObjectEndOrAttributeSep in the class io.nats.jparse.source.CharArrayCharSource is used to search for either the end of an object or an attribute separator in a character array.

Here is a step-by-step description of what this method is doing:

  1. Set the initial value of the variable i to the current index value.
  2. Set the initial value of the variable ch to zero.
  3. Get the reference to the character array data and the length of the array.
  4. Start a loop to iterate through the elements of the character array, starting from the current index i and ending at the last element of the array.
  5. Within the loop, assign the current element of the character array to the variable ch.
  6. Use a switch statement to check the value of ch against two possible cases: a. If ch matches the constant OBJECT_END_TOKEN, update the current index index to i + 1 and return true to indicate that the end of an object has been found. b. If ch matches the constant ATTRIBUTE_SEP, update the current index index to i and return false to indicate that an attribute separator has been found.
  7. If none of the above cases match for any element of the character array, throw an UnexpectedCharacterException with a detailed message indicating that the method was trying to parse an object key, while searching for either the object end or separator.
  8. End of the loop.

In summary, the method iterates through the character array data starting from the current index index and checks if each character matches either the object end token or the attribute separator. If a match is found, it updates the current index and returns a boolean value indicating the result. If no match is found, it throws an exception. sequence diagram

@Override

public boolean findCommaOrEndForArray()

@Override
public boolean findCommaOrEndForArray() {
    int i = index;
    char ch = 0;
    final char[] data = this.data;
    final int length = data.length;
    for (; i < length; i++) {
        ch = data[i];
        switch(ch) {
            case ARRAY_END_TOKEN:
                this.index = i + 1;
                return true;
            case ARRAY_SEP:
                this.index = i;
                return false;
            case NEW_LINE_WS:
            case CARRIAGE_RETURN_WS:
            case TAB_WS:
            case SPACE_WS:
                continue;
            default:
                throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this, ch, i);
        }
    }
    throw new UnexpectedCharacterException("Parsing Array", "Finding list end or separator", this);
}

The findCommaOrEndForArray method in the CharArrayCharSource class is used to find the comma or end token within an array. Here is a step-by-step description of what the method does:

  1. Start at the current index stored in the index variable.
  2. Initialize a temporary variable ch to store the current character being examined.
  3. Get the character array data from the instance variable this.data.
  4. Get the length of the character array in the length variable.
  5. Start a loop that iterates from the current index (i) to the length of the character array.
  6. Get the character at the current index (i) and store it in the ch variable.
  7. Use a switch statement to check the value of ch.
  8. If the character is equal to the ARRAY_END_TOKEN, set the index variable to i + 1, indicating that the end of the array has been found. Then, return true to indicate that the end token has been found.
  9. If the character is equal to the ARRAY_SEP, set the index variable to i, indicating that a comma separator has been found. Then, return false to indicate that a separator has been found.
  10. If the character is one of the defined whitespace characters (NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS), skip the current iteration of the loop and continue to the next character.
  11. If the character does not match any of the expected values, throw an UnexpectedCharacterException with the appropriate error message and include information about the current character and its index.
  12. If the end of the array is reached without finding an end token or separator, throw an UnexpectedCharacterException with the appropriate error message and context information about the parsing operation.

This method is used to parse an input character array and determine whether the next character is an end token or a separator within an array, based on the defined array tokens and whitespace characters. It returns a boolean value indicating whether an end token has been found or not. sequence diagram

@Override

public int findNullEnd()

@Override
public int findNullEnd() {
    if (this.data[++index] == 'u' && this.data[++index] == 'l' && this.data[++index] == 'l') {
        return ++index;
    } else {
        throw new UnexpectedCharacterException("Parsing JSON Null", "Unexpected character", this);
    }
}

The findNullEnd method in the CharArrayCharSource class is used to find the end position of a "null" value in a JSON string.

Here is a step-by-step description of what the method does:

  1. The method overrides the findNullEnd method defined in the superclass, indicating that it provides a specific implementation for this method.

  2. The method begins by incrementing the value of the index variable by 1. This is done using the pre-increment operator ++ before the index variable. This means that the new value of index will be one greater than its previous value.

  3. The method then checks if the character at the new index position in the data array is equal to the character 'u'. If it is, the condition is true and the code block inside the if statement is executed.

  4. Inside the if statement, the value of index is again incremented by 1 using the pre-increment operator. This means that the new value of index will be one greater than its previous value.

  5. The method then checks if the character at the new index position in the data array is equal to the character 'l'. If it is, the condition is true and the code block inside the if statement is executed.

  6. Inside the if statement, the value of index is again incremented by 1 using the pre-increment operator. This means that the new value of index will be one greater than its previous value.

  7. The method then checks if the character at the new index position in the data array is equal to the character 'l'. If it is, the condition is true and the code block inside the if statement is executed.

  8. Inside the if statement, the value of index is once again incremented by 1 using the pre-increment operator. This means that the new value of index will be one greater than its previous value.

  9. After the if-else block, the method returns the value of index, incremented by 1 using the pre-increment operator. This means that the returned value will be one greater than its previous value.

  10. If any of the if conditions in steps 3, 5, or 7 evaluate to false, indicating that the "null" value was not found, an UnexpectedCharacterException is thrown. This exception provides an error message stating that "Parsing JSON Null" failed because an unexpected character was encountered in the CharArrayCharSource, and includes a reference to the source object.

In summary, the findNullEnd method in the CharArrayCharSource class is responsible for locating the end position of a "null" value in a JSON string. It checks if the characters at a specific position in the string match the sequence 'u', 'l', 'l', and returns the position of the last character of the match. If the expected sequence is not found, an exception is thrown. sequence diagram

@Override

public boolean matchChars(final int startIndex, final int endIndex, CharSequence key)

@Override
public boolean matchChars(final int startIndex, final int endIndex, CharSequence key) {
    final int length = endIndex - startIndex;
    int idx = startIndex;
    switch(length) {
        case 1:
            return key.charAt(0) == data[idx];
        case 2:
            return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1];
        case 3:
            return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2];
        case 4:
            return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(3) == data[idx + 3];
        case 5:
            return key.charAt(1) == data[idx + 1] && key.charAt(3) == data[idx + 3] && key.charAt(0) == data[idx] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
        case 6:
            return key.charAt(0) == data[idx] && key.charAt(5) == data[idx + 5] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
        case 7:
            return key.charAt(0) == data[idx] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
        case 8:
            return key.charAt(0) == data[idx] && key.charAt(7) == data[idx + 7] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(4) == data[idx + 4];
        case 9:
            return key.charAt(0) == data[idx] && key.charAt(8) == data[idx + 8] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1];
        case 10:
            return key.charAt(0) == data[idx] && key.charAt(9) == data[idx + 9] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
        case 11:
            return key.charAt(0) == data[idx] && key.charAt(10) == data[idx + 10] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
        case 12:
            return key.charAt(0) == data[idx] && key.charAt(11) == data[idx + 11] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(10) == data[idx + 10] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
        default:
            final int start = 0;
            final int end = length - 1;
            final int middle = length / 2;
            if (key.charAt(start) == data[idx] && key.charAt(end) == data[idx + end] && key.charAt(middle) == data[idx + middle]) {
                for (int i = 1; i < length; i++) {
                    if (key.charAt(i) != data[idx + i]) {
                        return false;
                    }
                }
                return true;
            } else {
                return false;
            }
    }
}

The matchChars method is a method defined in the CharArrayCharSource class, which is used for comparing a character sequence with a portion of a character array.

Here's a step-by-step description of what the method does:

  1. The method takes three parameters: startIndex, endIndex, and key. These parameters indicate the range of the character array to be compared and the character sequence to compare it with.

  2. The method calculates the length of the character array range by subtracting the startIndex from the endIndex.

  3. It initializes a variable idx with the value of the startIndex.

  4. The method then uses a switch statement based on the length of the character array range:

    • For lengths 1 to 12, it compares each corresponding character in the key sequence with the corresponding character in the character array range using the charAt method. If all the characters match, it returns true, otherwise false.

    • For lengths greater than 12, it performs a more generic comparison. It checks if the first, middle, and last characters of the key sequence match the corresponding characters in the character array range. If they do, it iterates through the rest of the characters in the key sequence and character array range, comparing each character. If all the characters match, it returns true, otherwise false.

    • If none of the above cases match, it returns false.

Overall, the matchChars method is used to determine if a given character sequence matches a specific portion of a character array. It uses a combination of specific comparisons for shorter lengths and a more generic comparison for longer lengths. sequence diagram

public boolean isInteger(int offset, int end)

public boolean isInteger(int offset, int end) {
    int len = end - offset;
    final char[] digitChars = data;
    final boolean negative = (digitChars[offset] == '-');
    final int cmpLen = negative ? MIN_INT_STR_LENGTH : MAX_INT_STR_LENGTH;
    if (len < cmpLen)
        return true;
    if (len > cmpLen)
        return false;
    final char[] cmpStr = negative ? MIN_INT_CHARS : MAX_INT_CHARS;
    for (int i = 0; i < cmpLen; ++i) {
        int diff = digitChars[offset + i] - cmpStr[i];
        if (diff != 0) {
            return (diff < 0);
        }
    }
    return true;
}

The isInteger method, defined in the io.nats.jparse.source.CharArrayCharSource class, determines whether a sequence of characters in an array represents an integer. The method takes in two parameters - offset and end, which specify the range of characters in the array to be considered.

Here is a step-by-step description of what the method does based on its body:

  1. Calculate the length of the sequence by subtracting the offset from the end parameter and store it in the len variable.
  2. Get a reference to the character array (data) that contains the sequence of characters to be examined.
  3. Determine whether the first character in the sequence is a negative sign ('-') and store the result in the negative variable.
  4. Determine whether the length of the sequence (len) is less than a predefined length for comparisons (MIN_INT_STR_LENGTH or MAX_INT_STR_LENGTH). If it is, return true since the sequence is shorter than the minimum length required for a valid integer representation.
  5. If the length of the sequence is longer than the predefined length, return false since the sequence is longer than the maximum length required for a valid integer representation.
  6. Determine which predefined character array to use for comparison (MIN_INT_CHARS or MAX_INT_CHARS), based on whether the sequence represents a negative or positive integer, and store it in the cmpStr variable.
  7. Iterate over each character in the sequence, comparing it with the corresponding character in the predefined character array.
  8. In each iteration, calculate the difference between the current character in the sequence and the corresponding character in the predefined character array and store it in the diff variable.
  9. If the difference is non-zero, return true if the difference is less than zero, indicating that the sequence is a smaller number than the predefined comparison value.
  10. If all characters in the sequence match the corresponding characters in the predefined character array, return true to indicate that the sequence represents a valid integer.
  11. If no non-zero differences are found, return true since the sequence matches the predefined comparison value.

In summary, the isInteger method determines whether a sequence of characters in an array represents an integer by comparing it with predefined character arrays and performing character-by-character comparisons. It handles cases where the sequence is too short or too long, and also distinguishes between negative and positive integers. sequence diagram

@Override

public String errorDetails(String message, int index, int ch)

@Override
public String errorDetails(String message, int index, int ch) {
    StringBuilder buf = new StringBuilder(255);
    final char[] array = data;
    buf.append(message).append("\n");
    buf.append("\n");
    buf.append("The current character read is " + debugCharDescription(ch)).append('\n');
    int line = 0;
    int lastLineIndex = 0;
    for (int i = 0; i < index && i < array.length; i++) {
        if (array[i] == '\n') {
            line++;
            lastLineIndex = i + 1;
        }
    }
    int count = 0;
    for (int i = lastLineIndex; i < array.length; i++, count++) {
        if (array[i] == '\n') {
            break;
        }
    }
    buf.append("line number " + (line + 1)).append('\n');
    buf.append("index number " + index).append('\n');
    try {
        buf.append(new String(array, lastLineIndex, count)).append('\n');
    } catch (Exception ex) {
        try {
            int start = index = (index - 10 < 0) ? 0 : index - 10;
            buf.append(new String(array, start, index)).append('\n');
        } catch (Exception ex2) {
            buf.append(new String(array)).append('\n');
        }
    }
    for (int i = 0; i < (index - lastLineIndex); i++) {
        buf.append('.');
    }
    buf.append('^');
    return buf.toString();
}

Method errorDetails

This method, defined in the class io.nats.jparse.source.CharArrayCharSource, is used to generate an error message with details about the error encountered at a specific index in the character array.

Signature

public String errorDetails(String message, int index, int ch)

Parameters

  • message (String): A custom error message to prepend to the error details.
  • index (int): The index at which the error occurred in the character array.
  • ch (int): The current character being processed when the error occurred.

Return Value

  • String: The generated error message with details.

Steps

  1. Create a StringBuilder instance named buf, initialized with an initial capacity of 255.
  2. Create a local variable named array of type char[], initialized with the character array data from the class.
  3. Append the message parameter and a newline character to buf.
  4. Append an additional newline character to buf.
  5. Append a formatted string to buf that describes the current character being processed, using the debugCharDescription method.
  6. Initialize two local variables, line and lastLineIndex, both set to 0.
  7. Iterate from i = 0 to index, exclusive, and as long as i is within the length of array.
    • If the character array[i] is a newline character, increment line by 1 and update lastLineIndex to i + 1.
  8. Initialize two local variables, count set to 0, and i set to lastLineIndex.
  9. Iterate from i = lastLineIndex to the end of array.
    • If the character array[i] is a newline character, break the loop.
    • Otherwise, increment count by 1.
  10. Append a formatted string to buf that states the line number, which is line + 1.
  11. Append a formatted string to buf that states the index number, which is index.
  12. Attempt the following block, and catch any exceptions thrown:
    • Append a substring of array to buf, starting at lastLineIndex with a length of count.
  13. If an exception was caught in the above block, attempt the following block, and catch any exceptions thrown:
    • Calculate the start index by subtracting 10 from index. If the result is less than 0, set start to 0.
    • Append a substring of array to buf, starting at start with a length of index.
  14. If an exception was caught in the above block, append the entire array to buf.
  15. Append a sequence of dots (.) to buf, equal to the difference between index and lastLineIndex.
  16. Append a ^ character to buf.
  17. Return the string representation of buf. sequence diagram

Clone this wiki locally