/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.ast; import java.util.Arrays; /** * Calculates from an absolute offset in the source file the line/column * coordinate. This is needed as Rhino only offers absolute positions for each * node. Some other languages like XML and Apex use this, too. * * Idea from: * http://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/javascript/jscomp/SourceFile.java */ public class SourceCodePositioner { private int[] lineOffsets; private int sourceCodeLength; public SourceCodePositioner(String sourceCode) { analyzeLineOffsets(sourceCode); } private void analyzeLineOffsets(String sourceCode) { String[] lines = sourceCode.split("\n"); sourceCodeLength = sourceCode.length(); int startOffset = 0; int lineNumber = 0; lineOffsets = new int[lines.length]; for (String line : lines) { lineOffsets[lineNumber] = startOffset; lineNumber++; startOffset += line.length() + 1; // +1 for the "\n" character } } public int lineNumberFromOffset(int offset) { int search = Arrays.binarySearch(lineOffsets, offset); int lineNumber; if (search >= 0) { lineNumber = search; } else { int insertionPoint = search; insertionPoint += 1; insertionPoint *= -1; lineNumber = insertionPoint - 1; // take the insertion point one // before } return lineNumber + 1; // 1-based line numbers } public int columnFromOffset(int lineNumber, int offset) { int lineIndex = lineNumber - 1; if (lineIndex < 0 || lineIndex >= lineOffsets.length) { // no line number found... return 0; } int columnOffset = offset - lineOffsets[lineNumber - 1]; return columnOffset + 1; // 1-based column offsets } public int getLastLine() { return lineOffsets.length; } public int getLastLineColumn() { return columnFromOffset(getLastLine(), sourceCodeLength - 1); } }