1 /* 2 * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package oracle.code.json; 26 27 import java.util.Objects; 28 29 final class JsonDocumentInfo { 30 31 // Access to the underlying JSON contents 32 final char[] doc; 33 // tokens array/index are finalized by JsonParser::parse 34 final int[] tokens; 35 int index; 36 // For exception message on failure 37 int line = 0; 38 int lineStart = 0; 39 40 JsonDocumentInfo(char[] in) { 41 doc = in; 42 tokens = new int[doc.length]; 43 index = 0; 44 } 45 46 // Convenience to walk a token during inflation 47 boolean shouldWalkToken(char c) { 48 return switch (c) { 49 case '"', '{', '[' -> true; 50 default -> false; 51 }; 52 } 53 54 // gets offset in the input from the array index 55 int getOffset(int index) { 56 Objects.checkIndex(index, this.index); 57 return tokens[index]; 58 } 59 60 // Json Boolean, Null, and Number have an end index that is 1 greater 61 // If the root is a primitive JSON value, -1 is returned as there are no indices 62 int nextIndex(int index) { 63 if (index + 1 < this.index) { 64 return index + 1; 65 } else { 66 return -1; 67 } 68 } 69 70 // Json Array and Object have an end index that corresponds to the closing bracket 71 int nextIndex(int startIdx, char startToken, char endToken) { 72 var index = startIdx + 1; 73 int depth = 0; 74 while (index < this.index) { 75 var c = charAtIndex(index); 76 if (c == startToken) { 77 depth++; 78 } else if (c == endToken) { 79 depth--; 80 } 81 if (depth < 0) { 82 break; 83 } 84 index++; 85 } 86 return index; 87 } 88 89 // for convenience 90 char charAtIndex(int index) { 91 return doc[getOffset(index)]; 92 } 93 94 int getIndexCount() { 95 return index; 96 } 97 98 int getEndOffset() { 99 return doc.length; 100 } 101 102 // gets the char at the specified offset in the input 103 char charAt(int offset) { 104 return doc[offset]; 105 } 106 107 // gets the substring at the specified start/end offsets in the input 108 String substring(int startOffset, int endOffset) { 109 return new String(doc, startOffset, endOffset - startOffset); 110 } 111 112 // Utility method to compose parse exception message 113 String composeParseExceptionMessage(String message, int line, int lineStart, int offset) { 114 return message + ": (%s) at Row %d, Col %d." 115 .formatted(substring(offset, Math.min(offset + 8, doc.length)), line, offset - lineStart); 116 } 117 }