1 /* Copyright 2002-2019 CS Systèmes d'Information 2 * Licensed to CS Systèmes d'Information (CS) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * CS licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.orekit.files.ccsds; 18 19 import java.util.Locale; 20 import java.util.regex.Matcher; 21 import java.util.regex.Pattern; 22 23 import org.orekit.errors.OrekitException; 24 import org.orekit.errors.OrekitMessages; 25 26 /** Holder for key-value pair. 27 * <p> 28 * The syntax for key-value lines in CCSDS files is: 29 * </p> 30 * <pre> 31 * KEY = value [unit] 32 * </pre> 33 * <p> 34 * The "[unit]" part (with the square brackets included) is optional. 35 * The COMMENT keyword is an exception and does not have an '=' but directly 36 * the value as free form text. The META_START, META_STOP, COVARIANCE_START 37 * and COVARIANCE_STOP keywords are other exception and do not have anything 38 * else following them on the line. 39 * </p> 40 * @author Luc Maisonobe 41 * @since 6.1 42 */ 43 class KeyValue { 44 45 /** Regular expression for splitting lines. */ 46 private final Pattern PATTERN = 47 Pattern.compile("\\p{Space}*([A-Z][A-Z_0-9]*)\\p{Space}*=?\\p{Space}*(.*?)\\p{Space}*(?:\\[.*\\])?\\p{Space}*"); 48 49 /** Regular expression for user defined keywords. */ 50 private final Pattern USER_DEFINED_KEYWORDS = 51 Pattern.compile("USER_DEFINED_[A-Z][A-Z_]*"); 52 53 /** Line from which pair is extracted. */ 54 private final String line; 55 56 /** Number of the line from which pair is extracted. */ 57 private final int lineNumber; 58 59 /** Name of the file. */ 60 private final String fileName; 61 62 /** Keyword enum corresponding to parsed key. */ 63 private final Keyword keyword; 64 65 /** Key part of the pair. */ 66 private final String key; 67 68 /** Value part of the line. */ 69 private final String value; 70 71 /** Build a pair by splitting a key-value line. 72 * <p> 73 * The splitting is very basic and only extracts words using a regular 74 * expression ignoring the '=' sign and the optional unit. No attempt 75 * is made to recognize the special keywords. The key and value parts 76 * may be empty if not matched, and the keyword may be null. 77 * </p> 78 * <p> The value part may be upper case or lower case. This constructor 79 * converts all lower case values to upper case. 80 * @param line to split 81 * @param lineNumber number of the line in the CCSDS data message 82 * @param fileName name of the file 83 */ 84 KeyValue(final String line, final int lineNumber, final String fileName) { 85 86 this.line = line; 87 this.lineNumber = lineNumber; 88 this.fileName = fileName; 89 90 final Matcher matcher = PATTERN.matcher(line); 91 if (matcher.matches()) { 92 key = matcher.group(1); 93 final String rawValue = matcher.group(2); 94 Keyword recognized; 95 try { 96 recognized = Keyword.valueOf(key); 97 } catch (IllegalArgumentException iae) { 98 if (USER_DEFINED_KEYWORDS.matcher(key).matches()) { 99 recognized = Keyword.USER_DEFINED_X; 100 } else { 101 recognized = null; 102 } 103 } 104 keyword = recognized; 105 if (recognized == Keyword.COMMENT) { 106 value = rawValue; 107 } else { 108 value = rawValue. 109 toUpperCase(Locale.US). 110 replace('_', ' '). 111 replaceAll("\\p{Space}+", " "); 112 } 113 } else { 114 key = ""; 115 value = key; 116 keyword = null; 117 } 118 } 119 120 /** Build a pair by giving the input arguments. 121 * This is essentially used while parsing XML files. 122 * It is made to be allow the use of the class KeyValue for both Keyvalue and XML file formats. 123 * Thus common functions can be used for the parsing. 124 * <p> 125 * The splitting is very basic and only extracts words using a regular 126 * expression ignoring the '=' sign and the optional unit. No attempt 127 * is made to recognize the special keywords. The key and value parts 128 * may be empty if not matched, and the keyword may be null. 129 * </p> 130 * <p> The value part may be upper case or lower case. This constructor 131 * converts all lower case values to upper case. 132 * @param keyword the keyword 133 * @param value the value attached to the keyword 134 * @param line the line where the keyword was found 135 * @param lineNumber number of the line in the CCSDS data message 136 * @param fileName name of the file 137 */ 138 KeyValue(final Keyword keyword, final String value, 139 final String line, final int lineNumber, 140 final String fileName) { 141 this.keyword = keyword; 142 this.key = keyword.name(); 143 this.value = value; 144 this.lineNumber = lineNumber; 145 this.line = line; 146 this.fileName = fileName; 147 } 148 149 /** Keyword corresponding to the parsed key. 150 * @return keyword corresponding to the parsed key 151 * (null if not recognized) 152 */ 153 public Keyword getKeyword() { 154 return keyword; 155 } 156 157 /** Get the key. 158 * @return key 159 */ 160 public String getKey() { 161 return key; 162 } 163 164 /** Get the value. 165 * @return value 166 */ 167 public String getValue() { 168 return value; 169 } 170 171 /** Get the value as a double number. 172 * @return value 173 */ 174 public double getDoubleValue() { 175 try { 176 return Double.parseDouble(value); 177 } catch (NumberFormatException nfe) { 178 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, 179 lineNumber, fileName, line); 180 } 181 } 182 183 /** Get the value as an integer number. 184 * @return value 185 */ 186 public int getIntegerValue() { 187 try { 188 return Integer.parseInt(value); 189 } catch (NumberFormatException nfe) { 190 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE, 191 lineNumber, fileName, line); 192 } 193 } 194 195 }