/* Copyright (c) 2011 Danish Maritime Authority. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dk.dma.ais.sentence; import java.util.ArrayList; import java.util.List; import dk.dma.ais.proprietary.ProprietaryFactory; /** * Class representing a single sentence line */ public class SentenceLine { /** Cache of all ASCII strings with length 1 */ private static final String[] S1 = new String[256]; /** Cache of all ASCII strings with length 2 */ private static final String[] S2 = new String[256 * 256]; private String line; private String talker; private String formatter; private Character delimiter; private String prefix; private String sentence; private ArrayList<String> fields = new ArrayList<>(); private int checksum; private int checksumField = -1; static { for (int i = 0; i < 256; i++) { S1[i] = Character.toString((char) i); } for (int i = 0; i < 256; i++) { for (int j = 0; j < 256; j++) { S2[i * 256 + j] = new String(new char[] { (char) i, (char) j }); } } } public SentenceLine() {} public SentenceLine(String line) { parse(line); } public void clear() { line = null; talker = null; formatter = null; delimiter = null; prefix = null; sentence = null; fields.clear(); checksum = 0; checksumField = -1; } public void parse(String line) { clear(); this.line = line; int len = line.length(); int checksumStart = 0; int ptr = 0; // Find len without CR LF while (len > 0 && (line.charAt(len - 1) == '\r' || line.charAt(len - 1) == '\n')) { len--; } // Find prefix and start of sentence while (ptr < len) { char ch = line.charAt(ptr); if (ch == '!' || ch == '$') { delimiter = ch; checksumStart = ptr; break; } ptr++; } this.prefix = convertString(line, 0, ptr); if (this.delimiter == null) { return; } int ptrStart = ptr; int ps = ptr; // Parse into fields while (ptr < len) { char ch = line.charAt(ptr); if (ch == '*') { fields.add(convertString(line, ps, ptr)); this.checksumField = fields.size(); ps = ptr + 1; } else if (ch == ',') { fields.add(convertString(line, ps, ptr)); ps = ptr + 1; } if (ptr > checksumStart && this.checksumField < 0) { checksum ^= ch; } ptr++; } if (ps < len) { fields.add(convertString(line, ps, len)); } // Make sure that a checksum field was actually added if (this.checksumField >= fields.size()) { this.checksumField = -1; } sentence = convertString(line, ptrStart, len); // Parse talker and formatter String f = fields.get(0); if (f.length() == 6) { talker = convertString(f, 1, 3); formatter = convertString(f, 3, 6); } } private static String convertString(String f, int start, int end) { switch (end - start) { case 0: return ""; case 1: return S1[f.charAt(start)]; case 2: return S2[(f.charAt(start) << 8) + f.charAt(start + 1)]; default: return f.substring(start, end); } } public boolean isFormatter(String... formatters) { if (formatter == null) { return false; } for (String f : formatters) { if (formatter.equals(f)) { return true; } } return false; } public boolean hasSentence() { return sentence != null; } public int getPostfixStart() { if (checksumField < 0) { return -1; } return checksumField + 1; } public boolean isChecksumMatch() { String strChecksum = getChecksumField(); if (strChecksum == null) { return false; } try { if (Integer.parseInt(strChecksum, 16) != this.checksum) { return false; } } catch (NumberFormatException e) { return false; } return true; } public String getSentenceHead() { return delimiter == null || fields.size() == 0 ? null : fields.get(0); } public boolean isProprietary() { return ProprietaryFactory.isProprietaryTag(getSentenceHead()); } public int getChecksum() { return checksum; } public String getChecksumString() { String strChecksum = Integer.toString(checksum, 16).toUpperCase(); if (strChecksum.length() < 2) { strChecksum = "0" + strChecksum; } return strChecksum; } public String getChecksumField() { return this.checksumField >= 0 ? fields.get(this.checksumField) : null; } public String getLine() { return line; } public void setLine(String line) { this.line = line; } public String getTalker() { return talker; } public void setTalker(String talker) { this.talker = talker; } public String getFormatter() { return formatter; } public void setFormatter(String formatter) { this.formatter = formatter; } public Character getDelimiter() { return delimiter; } public void setDelimiter(Character delimiter) { this.delimiter = delimiter; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getSentence() { return sentence; } public void setSentence(String sentence) { this.sentence = sentence; } public List<String> getFields() { return fields; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("SentenceLine [line="); builder.append(line); builder.append(", talker="); builder.append(talker); builder.append(", formatter="); builder.append(formatter); builder.append(", delimiter="); builder.append(delimiter); builder.append(", prefix="); builder.append(prefix); builder.append(", sentence="); builder.append(sentence); builder.append(", fields="); builder.append(fields); builder.append("]"); return builder.toString(); } }