/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.cocoon.generation; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; import java.util.Map; import org.apache.avalon.framework.parameters.ParameterException; import org.apache.avalon.framework.parameters.Parameterizable; import org.apache.avalon.framework.parameters.Parameters; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.components.midi.xmidi.ByteLen; import org.apache.cocoon.components.midi.xmidi.Utils; import org.apache.cocoon.components.midi.xmidi.Constants; import org.apache.cocoon.components.source.SourceUtil; import org.apache.cocoon.environment.SourceResolver; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; import org.apache.excalibur.source.SourceNotFoundException; import org.apache.excalibur.source.SourceValidity; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; /** * Reads a standard MIDI file and generates SAX Events. * * The MIDI file parsing parts of this class are based on code from the XMidi project, written * by Peter Arthur Loeb (http://www.palserv.com/XMidi/) and used with permission. * The warranty disclaimer of the MIT license (http://www.opensource.org/licenses/mit-license.html) * applies to Peter Arthur Loeb's code. * * @author <a href="mailto:mark.leicester@energyintellect.com">Mark Leicester</a> * @author <a href="mailto:peter@palserv.com">Peter Loeb</a> */ public class XMidiGenerator extends AbstractGenerator implements Parameterizable { /** The input source */ protected Source inputSource; private boolean global_verbose; private boolean local_verbose; private static final boolean VERBOSE_DEFAULT = true; private boolean validateVerbosity(String verbose) { if (verbose.equalsIgnoreCase("TRUE")) { return true; } else if (verbose.equalsIgnoreCase("FALSE")) { return false; } return VERBOSE_DEFAULT; } public void parameterize(Parameters parameters) throws ParameterException { global_verbose = validateVerbosity(parameters.getParameter( "verbose", String.valueOf(VERBOSE_DEFAULT))); } /** * Recycle this component. * All instance variables are set to <code>null</code>. */ public void recycle() { if (null != this.inputSource) { super.resolver.release(this.inputSource); this.inputSource = null; } // Reinitialize variables initializeVariables(); super.recycle(); } /** * Setup the MIDI file generator. * Try to get the last modification date of the source for caching. */ public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException { super.setup(resolver, objectModel, src, par); // Initialize lookup tables initializeLookupTables(); try { this.inputSource = resolver.resolveURI(src); } catch (SourceException se) { throw SourceUtil.handle("Error resolving '" + src + "'.", se); } local_verbose = validateVerbosity( parameters.getParameter( "verbose", String.valueOf(global_verbose))); } /** * Generate the unique key. * This key must be unique inside the space of this component. * * @return The generated key hashes the src */ public java.io.Serializable getKey() { return this.inputSource.getURI(); } /** * Generate the validity object. * * @return The generated validity object or <code>null</code> if the * component is currently not cacheable. */ public SourceValidity getValidity() { return this.inputSource.getValidity(); } /** * Generate XML data. */ public void generate() throws IOException, SAXException, ProcessingException { try { if (getLogger().isDebugEnabled()) { getLogger().debug("Source " + super.source + " resolved to " + this.inputSource.getURI()); } parseMIDI(this.inputSource); } catch (SAXException e) { SourceUtil.handleSAXException(this.inputSource.getURI(), e); } } private int midiFormat; private Hashtable ffHash; private String[] chanArray; private String[] fArray; private int numTracks; private int trkCount; private String[] notes; private int[] register; private Hashtable contHash; /** * @param source */ private void parseMIDI(Source source) throws SAXException, SourceNotFoundException, IOException, ProcessingException { InputStream inputStream = source.getInputStream(); AttributesImpl attr = new AttributesImpl(); String text = ""; this.contentHandler.startDocument(); attr.addAttribute("", "VERSION", "VERSION", "CDATA", Constants.VERSION); this.contentHandler.startElement("", "XMidi", "XMidi", attr); boolean chunkFlag = true; while (chunkFlag) { // for each chunk byte[] hdr = new byte[8]; int r; r = inputStream.read(hdr); if (r == -1) { chunkFlag = false; continue; } if (r < 8) { this.getLogger().debug("Getting header"); } // get chunk id String cid = Utils.baToString(hdr, 0, 3); // get chunk length int len = Utils.baToInt(hdr, 4, 7); // get rest of chunk byte[] dta = new byte[len]; r = inputStream.read(dta); if (r < len) { throw new ProcessingException("Getting data"); } if (cid.equals("MThd")) { attr.clear(); attr.addAttribute("", "LENGTH", "LENGTH", "CDATA", "" + len); attr.addAttribute("", "TYPE", "TYPE", "CDATA", cid); this.contentHandler.startElement("", "MThd", "MThd", attr); midiFormat = Utils.baToInt(dta, 0, 1); numTracks = Utils.baToInt(dta, 2, 3); String pnq = Utils.baToHex(dta, 4, 5); attr.clear(); this.contentHandler.startElement("", "FORMAT", "FORMAT", attr); text = "" + midiFormat; this.contentHandler.characters( text.toCharArray(), 0, text.length()); this.contentHandler.endElement("", "FORMAT", "FORMAT"); this.contentHandler.startElement("", "TRACKS", "TRACKS", attr); text = "" + numTracks; this.contentHandler.characters( text.toCharArray(), 0, text.length()); this.contentHandler.endElement("", "TRACKS", "TRACKS"); this.contentHandler.startElement("", "PPNQ", "PPNQ", attr); text = pnq; this.contentHandler.characters( text.toCharArray(), 0, text.length()); this.contentHandler.endElement("", "PPNQ", "PPNQ"); this.contentHandler.endElement("", "MThd", "MThd"); } else if (cid.equals("MTrk")) { trkCount++; if (trkCount > numTracks) { throw new ProcessingException("too many tracks"); } attr.clear(); attr.addAttribute("", "LENGTH", "LENGTH", "CDATA", "" + len); attr.addAttribute("", "TYPE", "TYPE", "CDATA", cid); this.contentHandler.startElement("", "MTrk", "MTrk", attr); doTrack(dta, len); this.contentHandler.endElement("", "MTrk", "MTrk"); } else { attr.clear(); attr.addAttribute("", "LENGTH", "LENGTH", "CDATA", "" + len); attr.addAttribute("", "TYPE", "TYPE", "CDATA", cid); this.contentHandler.startElement("", "CHUNK", "CHUNK", attr); doHexData(dta, len); this.contentHandler.endElement("", "CHUNK", "CHUNK"); } } this.contentHandler.endElement("", "XMidi", "XMidi"); this.contentHandler.endDocument(); } void initializeVariables() { numTracks = 0; trkCount = 0; } void initializeLookupTables() { ffHash = new Hashtable(); ffHash.put("00", "Sequence Number"); ffHash.put("01", "Text"); ffHash.put("02", "Copyright"); ffHash.put("03", "Sequence/Track Name"); ffHash.put("04", "Instrument"); ffHash.put("05", "Lyric"); ffHash.put("06", "Marker"); ffHash.put("07", "Cue Point"); ffHash.put("20", "MIDI Channel"); ffHash.put("21", "MIDI Port"); ffHash.put("2F", "End of Track"); ffHash.put("51", "Tempo"); ffHash.put("54", "SMPTE Offset"); ffHash.put("58", "Time Signature"); ffHash.put("59", "Key Signature"); ffHash.put("7F", "Proprietary Event"); chanArray = new String[7]; chanArray[0] = "Note Off"; chanArray[1] = "Note On"; chanArray[2] = "After Touch"; chanArray[3] = "Control Change"; chanArray[4] = "Program Change"; chanArray[5] = "Channel Pressure"; chanArray[6] = "Pitch Wheel"; fArray = new String[16]; fArray[0] = "SYSEX"; fArray[1] = "MTC Quarter Frame Message"; fArray[2] = "Song Position Pointer"; fArray[3] = "Song Select"; fArray[4] = "Undefined"; fArray[5] = "Undefined"; fArray[6] = "Tune Request"; fArray[7] = "Unsupported"; fArray[8] = "MIDI Clock"; fArray[9] = "Undefined"; fArray[10] = "MIDI Start"; fArray[11] = "MIDI Continue"; fArray[12] = "MIDI Stop"; fArray[13] = "Undefined"; fArray[14] = "Active Sense"; fArray[15] = "NotUnderstood"; contHash = new Hashtable(); contHash.put("0", "Bank Select"); contHash.put("1", "Modulation Wheel (coarse)"); contHash.put("2", "Breath controller (coarse)"); contHash.put("4", "Foot Pedal (coarse)"); contHash.put("5", "Portamento Time (coarse)"); contHash.put("6", "Data Entry (coarse)"); contHash.put("7", "Volume (coarse)"); contHash.put("8", "Balance (coarse)"); contHash.put("10", "Pan position (coarse)"); contHash.put("11", "Expression (coarse)"); contHash.put("12", "Effect Control 1 (coarse)"); contHash.put("13", "Effect Control 2 (coarse)"); contHash.put("16", "General Purpose Slider 1"); contHash.put("17", "General Purpose Slider 2"); contHash.put("18", "General Purpose Slider 3"); contHash.put("19", "General Purpose Slider 4"); contHash.put("32", "Bank Select (fine)"); contHash.put("33", "Modulation Wheel (fine)"); contHash.put("34", "Breath controller (fine)"); contHash.put("36", "Foot Pedal (fine)"); contHash.put("37", "Portamento Time (fine)"); contHash.put("38", "Data Entry (fine)"); contHash.put("39", "Volume (fine)"); contHash.put("40", "Balance (fine)"); contHash.put("42", "Pan position (fine)"); contHash.put("43", "Expression (fine)"); contHash.put("44", "Effect Control 1 (fine)"); contHash.put("45", "Effect Control 2 (fine)"); contHash.put("64", "Hold Pedal (on/off)"); contHash.put("65", "Portamento (on/off)"); contHash.put("66", "Sustenuto Pedal (on/off)"); contHash.put("67", "Soft Pedal (on/off)"); contHash.put("68", "Legato Pedal (on/off)"); contHash.put("69", "Hold 2 Pedal (on/off)"); contHash.put("70", "Sound Variation"); contHash.put("71", "Sound Timbre"); contHash.put("72", "Sound Release Time"); contHash.put("73", "Sound Attack Time"); contHash.put("74", "Sound Brightness"); contHash.put("75", "Sound Control 6"); contHash.put("76", "Sound Control 7"); contHash.put("77", "Sound Control 8"); contHash.put("78", "Sound Control 9"); contHash.put("79", "Sound Control 10"); contHash.put("80", "General Purpose Button 1 (on/off)"); contHash.put("81", "General Purpose Button 2 (on/off)"); contHash.put("82", "General Purpose Button 3 (on/off)"); contHash.put("83", "General Purpose Button 4 (on/off)"); contHash.put("91", "Effects Level"); contHash.put("92", "Tremulo Level"); contHash.put("93", "Chorus Level"); contHash.put("94", "Celeste Level"); contHash.put("95", "Phaser Level"); contHash.put("96", "Data Button increment"); contHash.put("97", "Data Button decrement"); contHash.put("98", "Non-registered Parameter (fine)"); contHash.put("99", "Non-registered Parameter (coarse)"); contHash.put("100", "Registered Parameter (fine)"); contHash.put("101", "Registered Parameter (coarse)"); contHash.put("120", "All Sound Off"); contHash.put("121", "All Controllers Off"); contHash.put("122", "Local Keyboard (on/off)"); contHash.put("123", "All Notes Off"); contHash.put("124", "Omni Mode Off"); contHash.put("125", "Omni Mode On"); contHash.put("126", "Mono Operation"); contHash.put("127", "Poly Operation"); notes = new String[128]; register = new int[128]; notes[0] = "C"; register[0] = -5; notes[1] = "C#"; register[1] = -5; notes[2] = "D"; register[2] = -5; notes[3] = "Eb"; register[3] = -5; notes[4] = "E"; register[4] = -5; notes[5] = "F"; register[5] = -5; notes[6] = "F#"; register[6] = -5; notes[7] = "G"; register[7] = -5; notes[8] = "Ab"; register[8] = -5; notes[9] = "A"; register[9] = -5; notes[10] = "Bb"; register[10] = -5; notes[11] = "B"; register[11] = -5; notes[12] = "C"; register[12] = -4; notes[13] = "C#"; register[13] = -4; notes[14] = "D"; register[14] = -4; notes[15] = "Eb"; register[15] = -4; notes[16] = "E"; register[16] = -4; notes[17] = "F"; register[17] = -4; notes[18] = "F#"; register[18] = -4; notes[19] = "G"; register[19] = -4; notes[20] = "Ab"; register[20] = -4; notes[21] = "A"; register[21] = -4; notes[22] = "Bb"; register[22] = -4; notes[23] = "B"; register[23] = -4; notes[24] = "C"; register[24] = -3; notes[25] = "C#"; register[25] = -3; notes[26] = "D"; register[26] = -3; notes[27] = "Eb"; register[27] = -3; notes[28] = "E"; register[28] = -3; notes[29] = "F"; register[29] = -3; notes[30] = "F#"; register[30] = -3; notes[31] = "G"; register[31] = -3; notes[32] = "Ab"; register[32] = -3; notes[33] = "A"; register[33] = -3; notes[34] = "Bb"; register[34] = -3; notes[35] = "B"; register[35] = -3; notes[36] = "C"; register[36] = -2; notes[37] = "C#"; register[37] = -2; notes[38] = "D"; register[38] = -2; notes[39] = "Eb"; register[39] = -2; notes[40] = "E"; register[40] = -2; notes[41] = "F"; register[41] = -2; notes[42] = "F#"; register[42] = -2; notes[43] = "G"; register[43] = -2; notes[44] = "Ab"; register[44] = -2; notes[45] = "A"; register[45] = -2; notes[46] = "Bb"; register[46] = -2; notes[47] = "B"; register[47] = -2; notes[48] = "C"; register[48] = -1; notes[49] = "C#"; register[49] = -1; notes[50] = "D"; register[50] = -1; notes[51] = "Eb"; register[51] = -1; notes[52] = "E"; register[52] = -1; notes[53] = "F"; register[53] = -1; notes[54] = "F#"; register[54] = -1; notes[55] = "G"; register[55] = -1; notes[56] = "Ab"; register[56] = -1; notes[57] = "A"; register[57] = -1; notes[58] = "Bb"; register[58] = -1; notes[59] = "B"; register[59] = -1; notes[60] = "C"; register[60] = 0; notes[61] = "C#"; register[61] = 0; notes[62] = "D"; register[62] = 0; notes[63] = "Eb"; register[63] = 0; notes[64] = "E"; register[64] = 0; notes[65] = "F"; register[65] = 0; notes[66] = "F#"; register[66] = 0; notes[67] = "G"; register[67] = 0; notes[68] = "Ab"; register[68] = 0; notes[69] = "A"; register[69] = 0; notes[70] = "Bb"; register[70] = 0; notes[71] = "B"; register[71] = 0; notes[72] = "C"; register[72] = 1; notes[73] = "C#"; register[73] = 1; notes[74] = "D"; register[74] = 1; notes[75] = "Eb"; register[75] = 1; notes[76] = "E"; register[76] = 1; notes[77] = "F"; register[77] = 1; notes[78] = "F#"; register[78] = 1; notes[79] = "G"; register[79] = 1; notes[80] = "Ab"; register[80] = 1; notes[81] = "A"; register[81] = 1; notes[82] = "Bb"; register[82] = 1; notes[83] = "B"; register[83] = 1; notes[84] = "C"; register[84] = 2; notes[85] = "C#"; register[85] = 2; notes[86] = "D"; register[86] = 2; notes[87] = "Eb"; register[87] = 2; notes[88] = "E"; register[88] = 2; notes[89] = "F"; register[89] = 2; notes[90] = "F#"; register[90] = 2; notes[91] = "G"; register[91] = 2; notes[92] = "Ab"; register[92] = 2; notes[93] = "A"; register[93] = 2; notes[94] = "Bb"; register[94] = 2; notes[95] = "B"; register[95] = 2; notes[96] = "C"; register[96] = 3; notes[97] = "C#"; register[97] = 3; notes[98] = "D"; register[98] = 3; notes[99] = "Eb"; register[99] = 3; notes[100] = "E"; register[100] = 3; notes[101] = "F"; register[101] = 3; notes[102] = "F#"; register[102] = 3; notes[103] = "G"; register[103] = 3; notes[104] = "Ab"; register[104] = 3; notes[105] = "A"; register[105] = 3; notes[106] = "Bb"; register[106] = 3; notes[107] = "B"; register[107] = 3; notes[108] = "C"; register[108] = 4; notes[109] = "C#"; register[109] = 4; notes[110] = "D"; register[110] = 4; notes[111] = "Eb"; register[111] = 4; notes[112] = "E"; register[112] = 4; notes[113] = "F"; register[113] = 4; notes[114] = "F#"; register[114] = 4; notes[115] = "G"; register[115] = 4; notes[116] = "Ab"; register[116] = 4; notes[117] = "A"; register[117] = 4; notes[118] = "Bb"; register[118] = 4; notes[119] = "B"; register[119] = 4; notes[120] = "C"; register[120] = 5; notes[121] = "C#"; register[121] = 5; notes[122] = "D"; register[122] = 5; notes[123] = "Eb"; register[123] = 5; notes[124] = "E"; register[124] = 5; notes[125] = "F"; register[125] = 5; notes[126] = "F#"; register[126] = 5; notes[127] = "G"; register[127] = 5; } /** * Add track data to DOM structure */ void doTrack(byte[] dta, int len) throws SAXException, ProcessingException { AttributesImpl attr = new AttributesImpl(); String text = ""; boolean tFlag = true; int offset = 0; // initialize variables String edata = null; String snam = null; String nmData = ""; String ctag = null; String ctagAttr[] = new String[4]; String ctagAttrVal[] = new String[4]; int ctagnum = 0; String cnum = null; String ctyp = null; int slen = 0; int chanType = 0; int hiName = 0; int status = 0; int noff = 0; String sval = null; boolean ecFlag = true; // assume edata boolean nFlag = true; // use slen for noff boolean firstTime = true; while (tFlag) { // do delta ByteLen bl = Utils.deltaToInt(dta, offset); offset += bl.len; String deltaLen = Utils.baToHex(bl.ba, 0, 3); nFlag = true; // assume simple (slen) offset // may or may not be status boolean statFlag = false; int first = Utils.baToInt(dta, offset, offset); this.getLogger().debug( "doTrack: in loop; deltaLen=" + deltaLen + ", len=" + bl.len + ", first=" + first); if ((first & 128) == 128) { // it is a status byte statFlag = true; sval = Utils.baToHex(dta, offset, offset); status = first; this.getLogger().debug("doTrack: have status: " + sval); if (status < 240 && status > 127) { ecFlag = false; chanType = (status - 128) / 16; snam = chanArray[chanType]; ctyp = sval.substring(0, 1); cnum = sval.substring(1, 2); } else { ecFlag = true; if (status > 239 && status < 256) { hiName = status - 240; snam = fArray[hiName]; } else { throw new ProcessingException( "Invalid status: " + status); } } offset++; } else { this.getLogger().debug("doTrack: running status"); } nmData = ""; if (firstTime) { firstTime = false; if (!statFlag) { throw new ProcessingException( "first time, but no status; first = " + first); } } // offset points to the byte after the status // or first byte of "running status" attr.clear(); attr.addAttribute("", "DTIME", "DTIME", "CDATA", "" + deltaLen); this.contentHandler.startElement("", "DELTA", "DELTA", attr); if (status > 127 && status < 144) { // note off slen = 2; // set up tag int pitch = Utils.baToInt(dta, offset, offset); int vel = Utils.baToInt(dta, offset + 1, offset + 1); ctag = "NOTE_OFF"; ctagAttr[0] = "PITCH"; ctagAttrVal[0] = "" + pitch; ctagAttr[1] = "VELOCITY"; ctagAttrVal[1] = "" + vel; ctagnum = 2; if (local_verbose) { ctagAttr[2] = "NAME"; ctagAttrVal[2] = notes[pitch]; ctagAttr[3] = "REGISTER"; ctagAttrVal[3] = "" + register[pitch]; ctagnum = 4; } } else if (status > 143 && status < 160) { // note on slen = 2; int pitch = Utils.baToInt(dta, offset, offset); int vel = Utils.baToInt(dta, offset + 1, offset + 1); ctag = "NOTE_ON"; ctagAttr[0] = "PITCH"; ctagAttrVal[0] = "" + pitch; ctagAttr[1] = "VELOCITY"; ctagAttrVal[1] = "" + vel; ctagnum = 2; if (local_verbose) { ctagAttr[2] = "NAME"; ctagAttrVal[2] = notes[pitch]; ctagAttr[3] = "REGISTER"; ctagAttrVal[3] = "" + register[pitch]; ctagnum = 4; } } else if (status > 159 && status < 176) { // after touch slen = 2; int pitch = Utils.baToInt(dta, offset, offset); int pres = Utils.baToInt(dta, offset + 1, offset + 1); ctag = "AFTER"; ctagAttr[0] = "PITCH"; ctagAttrVal[0] = "" + pitch; ctagAttr[1] = "PRESSURE"; ctagAttrVal[1] = "" + pres; ctagnum = 2; if (local_verbose) { ctagAttr[2] = "NAME"; ctagAttrVal[2] = notes[pitch]; ctagAttr[3] = "REGISTER"; ctagAttrVal[3] = "" + register[pitch]; ctagnum = 4; } } else if (status > 175 && status < 192) { // control change slen = 2; int contnum = Utils.baToInt(dta, offset, offset); int contval = Utils.baToInt(dta, offset + 1, offset + 1); ctag = "CONTROL"; ctagAttr[0] = "NUMBER"; ctagAttrVal[0] = "" + contnum; ctagAttr[1] = "VALUE"; ctagAttrVal[1] = "" + contval; ctagnum = 2; if (local_verbose) { ctagAttr[2] = "NAME"; ctagAttrVal[2] = (String) contHash.get("" + contnum); ctagnum = 3; } } else if (status > 191 && status < 208) { // program (patch) change slen = 1; int patch = Utils.baToInt(dta, offset, offset); ctag = "PROGRAM"; ctagAttr[0] = "NUMBER"; ctagAttrVal[0] = "" + patch; ctagnum = 1; } else if (status > 207 && status < 224) { // channel pressure slen = 1; int pamt = Utils.baToInt(dta, offset, offset); ctag = "PRESSURE"; ctagAttr[0] = "AMOUNT"; ctagAttrVal[0] = "" + pamt; ctagnum = 1; } else if (status > 223 && status < 240) { // pitch wheel slen = 2; int pwamt = Utils.getPW(dta, offset); ctag = "WHEEL"; ctagAttr[0] = "AMOUNT"; ctagAttrVal[0] = "" + pwamt; ctagnum = 1; } else if (status == 240) { // sysex bl = Utils.deltaToInt(dta, offset); slen = Utils.baToInt(bl.ba, 0, 3); noff = bl.len; nFlag = false; edata = Utils.baToHex(dta, offset + noff, offset + noff + slen - 1); noff += slen; } else if (status == 255) { // non midi (reset only in "live" midi") nmData = Utils.baToHex(dta, offset, offset); // nmData = "SNMT=\""+nmDta+"\" "; snam = "non-MIDI"; String nmNam = (String) ffHash.get(nmData); if (nmNam != null) { snam += " - " + nmNam; } else { snam += " - Unknown"; } // int nmt = baToInt(dta,offset+1,offset+1); bl = Utils.deltaToInt(dta, offset + 1); slen = Utils.baToInt(bl.ba, 0, 3); noff = bl.len + 1; nFlag = false; if (slen == 0) { edata = "No data"; } else { edata = Utils.baToHex( dta, offset + noff, offset + noff + slen - 1); noff += slen; } this.getLogger().debug( "doTrack: status FF" + nmData + ", edata = " + edata); } else if (status == 241 || status == 243) { int tcv = dta[offset]; Integer tc = new Integer(tcv); edata = tc.toString(); slen = 1; } else if (status == 242) { int tcv = Utils.getPW(dta, offset); Integer tc = new Integer(tcv); edata = tc.toString(); slen = 2; } else if ( status == 246 || status == 248 || status == 250 || status == 251 || status == 252 || status == 254) { edata = "No data for " + snam; slen = 0; } else { // really unknown int ol = Utils.getNextHiOrd(dta, offset); edata = Utils.baToHex(dta, offset + 1, ol); ol -= offset + 1; slen = ol; } if (ecFlag) { if (statFlag) { attr.clear(); attr.addAttribute("", "SLEN", "SLEN", "CDATA", "" + slen); attr.addAttribute("", "SNAM", "SNAM", "CDATA", snam); if (!nmData.equals("")) { attr.addAttribute("", "SNMT", "SNMT", "CDATA", nmData); } attr.addAttribute("", "SVAL", "SVAL", "CDATA", sval); this.contentHandler.startElement( "", "STATUS", "STATUS", attr); attr.clear(); this.contentHandler.startElement( "", "EDATA", "EDATA", attr); text = edata; this.contentHandler.characters( text.toCharArray(), 0, text.length()); this.contentHandler.endElement("", "EDATA", "EDATA"); this.contentHandler.endElement("", "STATUS", "STATUS"); } else { attr.clear(); this.contentHandler.startElement( "", "EDATA", "EDATA", attr); text = edata; this.contentHandler.characters( text.toCharArray(), 0, text.length()); this.contentHandler.endElement("", "EDATA", "EDATA"); } } else { if (statFlag) { attr.clear(); attr.addAttribute("", "SLEN", "SLEN", "CDATA", "" + slen); attr.addAttribute("", "SNAM", "SNAM", "CDATA", snam); if (!nmData.equals("")) { attr.addAttribute("", "SNMT", "SNMT", "CDATA", nmData); } attr.addAttribute("", "SVAL", "SVAL", "CDATA", sval); this.contentHandler.startElement( "", "STATUS", "STATUS", attr); attr.clear(); attr.addAttribute("", "NUMBER", "NUMBER", "CDATA", cnum); attr.addAttribute("", "TYPE", "TYPE", "CDATA", ctyp); this.contentHandler.startElement( "", "CHANNEL", "CHANNEL", attr); attr.clear(); for (int c = 0; c < ctagnum; c++) { attr.addAttribute( "", ctagAttr[c], ctagAttr[c], "CDATA", ctagAttrVal[c]); } this.contentHandler.startElement("", ctag, ctag, attr); this.contentHandler.endElement("", ctag, ctag); this.contentHandler.endElement("", "CHANNEL", "CHANNEL"); this.contentHandler.endElement("", "STATUS", "STATUS"); } else { attr.clear(); attr.addAttribute("", "NUMBER", "NUMBER", "CDATA", cnum); attr.addAttribute("", "TYPE", "TYPE", "CDATA", ctyp); this.contentHandler.startElement( "", "CHANNEL", "CHANNEL", attr); attr.clear(); for (int c = 0; c < ctagnum; c++) { attr.addAttribute( "", ctagAttr[c], ctagAttr[c], "CDATA", ctagAttrVal[c]); } this.contentHandler.startElement("", ctag, ctag, attr); this.contentHandler.endElement("", ctag, ctag); this.contentHandler.endElement("", "CHANNEL", "CHANNEL"); } } this.contentHandler.endElement("", "DELTA", "DELTA"); if (nFlag) { offset += slen; } else { offset += noff; } if (offset >= len) { tFlag = false; } } } /** * Write formatted hex data to file */ void doHexData(byte[] dta, int len) throws ProcessingException, SAXException { AttributesImpl attr = new AttributesImpl(); String text = ""; this.contentHandler.startElement("", "HEXDATA", "HEXDATA", attr); StringBuffer bth = new StringBuffer(""); int bpl = 32; int r = len % bpl; int n = len / bpl; for (int i = 0; i < n; i++) { int strt = i * bpl; bth.append(Utils.baToHex(dta, strt, strt + bpl - 1)); } if (r > 0) { int strt = n * bpl; bth.append(Utils.baToHex(dta, strt, strt + r - 1)); } text = bth.toString(); this.contentHandler.characters(text.toCharArray(), 0, text.length()); this.contentHandler.endElement("", "HEXDATA", "HEXDATA"); } }