1 /* Copyright 2002-2025 CS GROUP 2 * Licensed to CS GROUP (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.utils.generation; 18 19 import java.io.IOException; 20 import java.util.List; 21 22 import org.hipparchus.util.FastMath; 23 import org.orekit.files.ccsds.utils.FileFormat; 24 import org.orekit.utils.AccurateFormatter; 25 import org.orekit.utils.Formatter; 26 import org.orekit.utils.units.Unit; 27 28 /** Generator for Key-Value Notation CCSDS messages. 29 * @author Luc Maisonobe 30 * @since 11.0 31 */ 32 public class KvnGenerator extends AbstractGenerator { 33 34 /** Comment keyword. */ 35 private static final String COMMENT = "COMMENT"; 36 37 /** Start suffix for sections. */ 38 private static final String START = "_START"; 39 40 /** Stop suffix for sections. */ 41 private static final String STOP = "_STOP"; 42 43 /** String format used for all key/value pair lines. **/ 44 private final String kvFormat; 45 46 /** Column number for aligning units. */ 47 private final int unitsColumn; 48 49 /** String format used for all comment lines. **/ 50 private final String commentFormat; 51 52 /** Simple constructor. 53 * @param output destination of generated output 54 * @param paddingWidth padding width for aligning the '=' sign 55 * (not counting the extra blank added before the '=' sign) 56 * @param outputName output name for error messages 57 * @param maxRelativeOffset maximum offset in seconds to use relative dates 58 * (if a date is too far from reference, it will be displayed as calendar elements) 59 * @param unitsColumn columns number for aligning units (if negative or zero, units are not output) 60 * @param formatter to format double and dates to string 61 * @see org.orekit.files.ccsds.ndm.tdm.TdmWriter#KVN_PADDING_WIDTH TdmWriter.KVN_PADDING_WIDTH 62 * @see org.orekit.files.ccsds.ndm.adm.aem.AemWriter#KVN_PADDING_WIDTH AemWriter.KVN_PADDING_WIDTH 63 * @see org.orekit.files.ccsds.ndm.adm.apm.ApmWriter#KVN_PADDING_WIDTH ApmWriter.KVN_PADDING_WIDTH 64 * @see org.orekit.files.ccsds.ndm.odm.opm.OpmWriter#KVN_PADDING_WIDTH OpmWriter.KVN_PADDING_WIDTH 65 * @see org.orekit.files.ccsds.ndm.odm.omm.OmmWriter#KVN_PADDING_WIDTH OmmWriter.KVN_PADDING_WIDTH 66 * @see org.orekit.files.ccsds.ndm.odm.oem.OemWriter#KVN_PADDING_WIDTH OemWriter.KVN_PADDING_WIDTH 67 * @see org.orekit.files.ccsds.ndm.odm.ocm.OcmWriter#KVN_PADDING_WIDTH OcmWriter.KVN_PADDING_WIDTH 68 */ 69 public KvnGenerator(final Appendable output, final int paddingWidth, 70 final String outputName, final double maxRelativeOffset, 71 final int unitsColumn, final Formatter formatter) { 72 super(output, outputName, maxRelativeOffset, unitsColumn > 0, formatter); 73 kvFormat = "%-" + FastMath.max(1, paddingWidth) + "s = %s"; 74 final StringBuilder builder = new StringBuilder(COMMENT); 75 builder.append(' '); 76 while (builder.length() < paddingWidth + 3) { 77 builder.append(' '); 78 } 79 builder.append("%s%n"); 80 this.unitsColumn = unitsColumn; 81 this.commentFormat = builder.toString(); 82 } 83 84 /** Simple constructor. 85 * @param output destination of generated output 86 * @param paddingWidth padding width for aligning the '=' sign 87 * (not counting the extra blank added before the '=' sign) 88 * @param outputName output name for error messages 89 * @param maxRelativeOffset maximum offset in seconds to use relative dates 90 * (if a date is too far from reference, it will be displayed as calendar elements) 91 * @param unitsColumn columns number for aligning units (if negative or zero, units are not output) 92 * @see org.orekit.files.ccsds.ndm.tdm.TdmWriter#KVN_PADDING_WIDTH TdmWriter.KVN_PADDING_WIDTH 93 * @see org.orekit.files.ccsds.ndm.adm.aem.AemWriter#KVN_PADDING_WIDTH AemWriter.KVN_PADDING_WIDTH 94 * @see org.orekit.files.ccsds.ndm.adm.apm.ApmWriter#KVN_PADDING_WIDTH ApmWriter.KVN_PADDING_WIDTH 95 * @see org.orekit.files.ccsds.ndm.odm.opm.OpmWriter#KVN_PADDING_WIDTH OpmWriter.KVN_PADDING_WIDTH 96 * @see org.orekit.files.ccsds.ndm.odm.omm.OmmWriter#KVN_PADDING_WIDTH OmmWriter.KVN_PADDING_WIDTH 97 * @see org.orekit.files.ccsds.ndm.odm.oem.OemWriter#KVN_PADDING_WIDTH OemWriter.KVN_PADDING_WIDTH 98 * @see org.orekit.files.ccsds.ndm.odm.ocm.OcmWriter#KVN_PADDING_WIDTH OcmWriter.KVN_PADDING_WIDTH 99 */ 100 public KvnGenerator(final Appendable output, final int paddingWidth, 101 final String outputName, final double maxRelativeOffset, 102 final int unitsColumn) { 103 this(output, paddingWidth, outputName, maxRelativeOffset, unitsColumn, new AccurateFormatter()); 104 } 105 106 /** {@inheritDoc} */ 107 @Override 108 public FileFormat getFormat() { 109 return FileFormat.KVN; 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 public void startMessage(final String root, final String messageTypeKey, final double version) throws IOException { 115 writeEntry(messageTypeKey, String.format(Formatter.STANDARDIZED_LOCALE, "%.1f", version), null, true); 116 } 117 118 /** {@inheritDoc} */ 119 @Override 120 public void endMessage(final String root) { 121 // nothing to do 122 } 123 124 /** {@inheritDoc} */ 125 @Override 126 public void writeComments(final List<String> comments) throws IOException { 127 for (final String comment : comments) { 128 writeRawData(String.format(Formatter.STANDARDIZED_LOCALE, commentFormat, comment)); 129 } 130 } 131 132 /** {@inheritDoc} */ 133 @Override 134 public void writeEntry(final String key, final String value, final Unit unit, final boolean mandatory) throws IOException { 135 if (value == null) { 136 complain(key, mandatory); 137 } else { 138 final String s = String.format(Formatter.STANDARDIZED_LOCALE, kvFormat, key, value); 139 writeRawData(s); 140 if (writeUnits(unit)) { 141 for (int column = s.length(); column < unitsColumn; ++column) { 142 writeRawData(' '); 143 } 144 writeRawData('['); 145 writeRawData(siToCcsdsName(unit.getName())); 146 writeRawData(']'); 147 } 148 newLine(); 149 } 150 } 151 152 /** {@inheritDoc} */ 153 @Override 154 public void enterSection(final String name) throws IOException { 155 writeRawData(name); 156 writeRawData(START); 157 newLine(); 158 super.enterSection(name); 159 } 160 161 /** {@inheritDoc} */ 162 @Override 163 public String exitSection() throws IOException { 164 final String name = super.exitSection(); 165 writeRawData(name); 166 writeRawData(STOP); 167 newLine(); 168 return name; 169 } 170 171 }