package org.das2.qds.util; import java.io.BufferedReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Stack; import java.util.StringTokenizer; import java.util.logging.Logger; import org.das2.datum.LoggerManager; import org.das2.qds.QDataSet; import org.das2.qds.WritableDataSet; import org.das2.qds.ops.Ops; import org.das2.util.monitor.ProgressMonitor; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; /** * Tool for parsing ODL found at the top of .STS files. * @author jbf */ public class OdlParser { private static final Logger logger= LoggerManager.getLogger("qdataset.ascii.odl"); /** * read the ODL off the top of the file, returning the ODL * in a string and leaving the InputStream pointed at the * line following the ODL. * @param r reader for the file which starts with ODL. The reader will be left pointing at the first non-ODL line. * @param record * @return the ODL header. * @throws java.io.IOException * @throws JSONException never */ public static String readOdl( BufferedReader r, JSONObject record ) throws IOException, JSONException { boolean notdone= true; Stack objectStack= new Stack<>(); Stack jsonStack= new Stack<>(); StringBuilder sb= new StringBuilder(); String line; HashSet keepers= new HashSet<>(); keepers.add("NAME"); keepers.add("FORMAT"); keepers.add("ALIAS"); keepers.add("UNITS"); keepers.add("TYPE"); try { while ( notdone && ( line= r.readLine() )!=null ) { StringTokenizer st= new StringTokenizer(line); while ( st.hasMoreTokens() ) { String s= st.nextToken(); if ( s.equals("END_OBJECT") ) { sb.append( " ".substring(0,2*(objectStack.size()-1)) ); } else { sb.append( " ".substring(0,2*objectStack.size()) ); } if ( s.equals("OBJECT") ) { sb.append(s).append(" "); s= st.nextToken(); // = sb.append(s).append(" "); s= st.nextToken(); // the name objectStack.push(s); sb.append(s).append(" "); if ( s.equals("RECORD") ) { if ( record==null ) { record= new JSONObject(); } record.put( "array", new JSONArray() ); jsonStack.add(record); } else if ( !jsonStack.empty() ) { JSONArray nextArray= new JSONArray(); JSONObject jo= new JSONObject(); jo.put( "array", nextArray ); jsonStack.add( jo ); } } else if ( s.equals( "END_OBJECT" ) ) { sb.append( s ).append(" "); sb.append("/* ").append(objectStack.pop()).append(" */"); if ( !jsonStack.empty() ) { JSONObject finishedObject= jsonStack.pop(); if ( !jsonStack.empty() ) { JSONObject thisObject= jsonStack.peek(); thisObject.getJSONArray("array").put(finishedObject); } } } else { if ( keepers.contains(s) && !jsonStack.empty() ) { String t= s; sb.append(s).append(" "); s= st.nextToken(); // = sb.append(s).append(" "); s= st.nextToken(); // the name sb.append(s).append(" "); JSONObject currentObject= jsonStack.peek(); currentObject.put( t, s ); } else { sb.append( s ).append( " " ); } } } if ( objectStack.isEmpty() ) { notdone= false; } sb.append("\n"); } } catch ( JSONException ex ) { throw new RuntimeException(ex); } return sb.toString(); } /** * read the stream based on the spec in record. * @param r the reader, pointed after the ODL header. * @param record * @param monitor * @return * @throws java.io.IOException */ public static QDataSet readStream( BufferedReader r, JSONObject record, ProgressMonitor monitor ) throws IOException { int fieldCount= getFieldCount( record ); AsciiParser parser= AsciiParser.newParser( fieldCount ); WritableDataSet result= parser.readStream( r, monitor ); ArrayList names= new ArrayList<>(); getNames( record, "", false, names ); BundleBuilder bbuild= new BundleBuilder(result.length(0)); for ( int i=0; i0) sb.append(","); JSONObject jo= array.getJSONObject(i); sb.append( getFormat(jo) ); } return sb.toString(); } } catch ( JSONException ex ) { throw new RuntimeException(ex); } } /** * return a list of names which can be requested. * @param record the node, typically then entire STS record. * @param name the name of the node, "" for the root. * @param includeComposite include the single-column names, for example BGSM as well as BGSM.X. * @param result null or the name of a list to collect the names. * @return */ public static String[] getNames( JSONObject record, String name, boolean includeComposite, List result ) { if ( result==null ) { result= new ArrayList<>(); } JSONArray array= record.optJSONArray("array"); int icol=0; for ( int i=0; i-1 ) { return new int[] { rr[0],rr[1] }; } } else { int[] rr= getColumns( thisObject, startColumn+icol, name.substring(s.length()+1) ); // +1 is for the period if ( rr[0]>-1 ) { return new int[] { rr[0],rr[1] }; } } } } icol += getFieldCount(thisObject); } return new int[] { -1, -1 }; } /** * return the data with the given name * @param record * @param ds * @param name * @return */ public static QDataSet getDataSet( JSONObject record, QDataSet ds, String name ) { int[] rr= getColumns( record, 0, name ); QDataSet result= formTimeTags( ds, record ); QDataSet yy; if ( rr[0]==-1 ) { throw new IllegalArgumentException("no such dataset: "+name); } else if (rr[0]==rr[1]) { yy= Ops.slice1( ds, rr[0] ); } else { yy= Ops.trim1( ds, rr[0], rr[1] ); } return Ops.link( result.property(QDataSet.DEPEND_0), yy ); } }