This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit e7f2f4c6b11725522dfe9326fe3ec00500d7cb34 Author: Sebastian Rühl <[email protected]> AuthorDate: Tue Apr 20 16:08:58 2021 +0200 plc4j: simple xml based reader --- .../resources/templates/java/io-template.java.ftlh | 3 +- plc4j/drivers/s7/src/test/java/S7IoTest.java | 134 +++++++++++ plc4j/drivers/s7/src/test/java/s7IoTest.java | 121 ---------- .../java/spi/generation/ReadBufferXmlBased.java | 264 +++++++++++++++++++++ .../java/spi/generation/WriteBufferXmlBased.java | 125 ++++------ 5 files changed, 449 insertions(+), 198 deletions(-) diff --git a/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh b/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh index 7c10357..bf7c604 100644 --- a/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh +++ b/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh @@ -218,8 +218,8 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO< ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]); </#if> </#if> - <#break> io.closeContext("${arrayField.name}"); + <#break> <#case "checksum"> <#assign checksumField = field> <#assign simpleTypeReference = checksumField.type> @@ -424,6 +424,7 @@ public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO< </#switch> </#list> + io.closeContext("${type.name}"); // Create the instance <#if helper.isDiscriminatedChildTypeDefinition()> return new ${type.name}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>); diff --git a/plc4j/drivers/s7/src/test/java/S7IoTest.java b/plc4j/drivers/s7/src/test/java/S7IoTest.java new file mode 100644 index 0000000..a96e27c --- /dev/null +++ b/plc4j/drivers/s7/src/test/java/S7IoTest.java @@ -0,0 +1,134 @@ +/* + 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. + */ + +import org.apache.plc4x.java.s7.readwrite.*; +import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO; +import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize; +import org.apache.plc4x.java.s7.readwrite.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.readwrite.types.DataTransportSize; +import org.apache.plc4x.java.spi.generation.ReadBufferXmlBased; +import org.apache.plc4x.java.spi.generation.WriteBufferXmlBased; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class S7IoTest { + + // TODO: delete when xml is good + boolean doneDesigningJavaXml = false; + + @Disabled("Till the output is aligned to the one of golang") + @Test + void TestS7MessageBytes() throws Exception { + String wantXml = + "<TPKTPacket>\n" + + " <protocolId bitLength=\"8\" dataType=\"uint8\">3</protocolId>\n" + + " <reserved bitLength=\"8\" dataType=\"uint8\">0</reserved>\n" + + " <len bitLength=\"16\" dataType=\"uint16\">29</len>\n" + + " <COTPPacket>\n" + + " <headerLength bitLength=\"8\" dataType=\"uint18\">5</headerLength>\n" + + " <tpduCode bitLength=\"8\" dataType=\"uint8\">240</tpduCode>\n" + + " <COTPPacketData>\n" + + " <eot bitLength=\"1\" dataType=\"bit\">false</eot>\n" + + " <tpduRef bitLength=\"7\" dataType=\"uint8\">13</tpduRef>\n" + + " </COTPPacketData>\n" + + " <parameters>\n" + + " <COTPParameter>\n" + + " <parameterType bitLength=\"8\" dataType=\"uint8\">192</parameterType>\n" + + " <parameterLength bitLength=\"8\" dataType=\"uint8\">1</parameterLength>\n" + + " <COTPParameterTpduSize>\n" + + " <COTPTpduSize bitLength=\"8\" dataType=\"uint8\" stringRepresentation=\"SIZE_4096\">12</COTPTpduSize>\n" + + " </COTPParameterTpduSize>\n" + + " </COTPParameter>\n" + + " </parameters>\n" + + " <S7Message>\n" + + " <protocolId bitLength=\"8\" dataType=\"uint8\">50</protocolId>\n" + + " <messageType bitLength=\"8\" dataType=\"uint8\">3</messageType>\n" + + " <reserved bitLength=\"16\" dataType=\"uint16\">0</reserved>\n" + + " <tpduReference bitLength=\"16\" dataType=\"uint16\">11</tpduReference>\n" + + " <parameterLength bitLength=\"16\" dataType=\"uint16\">2</parameterLength>\n" + + " <payloadLength bitLength=\"16\" dataType=\"uint16\">5</payloadLength>\n" + + " <S7MessageResponseData>\n" + + " <errorClass bitLength=\"8\" dataType=\"uint8\">0</errorClass>\n" + + " <errorCode bitLength=\"8\" dataType=\"uint8\">0</errorCode>\n" + + " </S7MessageResponseData>\n" + + " <S7Parameter>\n" + + " <parameterType bitLength=\"8\" dataType=\"uint8\">4</parameterType>\n" + + " <S7ParameterReadVarResponse>\n" + + " <numItems bitLength=\"8\" dataType=\"uint8\">1</numItems>\n" + + " </S7ParameterReadVarResponse>\n" + + " </S7Parameter>\n" + + " <S7Payload>\n" + + " <S7PayloadReadVarResponse>\n" + + " <items>\n" + + " <S7VarPayloadDataItem>\n" + + " <DataTransportErrorCode bitLength=\"8\" dataType=\"uint8\" stringRepresentation=\"OK\">255</DataTransportErrorCode>\n" + + " <DataTransportSize bitLength=\"8\" dataType=\"uint8\" stringRepresentation=\"BIT\">3</DataTransportSize>\n" + + " <dataLength bitLength=\"16\" dataType=\"uint16\">1</dataLength>\n" + + " <data>\n" + + " <value bitLength=\"8\" dataType=\"int8\">1</value>\n" + + " </data>\n" + + " <padding></padding>\n" + + " </S7VarPayloadDataItem>\n" + + " </items>\n" + + " </S7PayloadReadVarResponse>\n" + + " </S7Payload>\n" + + " </S7Message>\n" + + " </COTPPacket>\n" + + "</TPKTPacket>\n"; + + + TPKTPacket tpktPacket = new TPKTPacket( + new COTPPacketData( + new COTPParameter[]{new COTPParameterTpduSize(COTPTpduSize.SIZE_4096)}, + new S7MessageResponseData( + 11, + new S7ParameterReadVarResponse((short) 1), + new S7PayloadReadVarResponse( + new S7VarPayloadDataItem[]{ + new S7VarPayloadDataItem( + DataTransportErrorCode.OK, + DataTransportSize.BIT, + new byte[]{0x1} + ) + } + ), + (short) 0, + (short) 0 + ), + false, + (short) 13 + ) + ); + WriteBufferXmlBased writeBufferXmlBased = new WriteBufferXmlBased(); + TPKTPacketIO.staticSerialize(writeBufferXmlBased, tpktPacket); + String gotXml = writeBufferXmlBased.getXmlString(); + if (doneDesigningJavaXml) { + assertEquals(wantXml, gotXml); + } + System.out.println(gotXml); + ReadBufferXmlBased readBufferXmlBased = new ReadBufferXmlBased(new ByteArrayInputStream(gotXml.getBytes())); + TPKTPacket reReadTpktPacket = TPKTPacketIO.staticParse(readBufferXmlBased); + assertThat(reReadTpktPacket).usingRecursiveComparison().isEqualTo(tpktPacket); + } +} diff --git a/plc4j/drivers/s7/src/test/java/s7IoTest.java b/plc4j/drivers/s7/src/test/java/s7IoTest.java deleted file mode 100644 index 977cb9b..0000000 --- a/plc4j/drivers/s7/src/test/java/s7IoTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - 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. - */ - -import org.apache.plc4x.java.s7.readwrite.*; -import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO; -import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize; -import org.apache.plc4x.java.s7.readwrite.types.DataTransportErrorCode; -import org.apache.plc4x.java.s7.readwrite.types.DataTransportSize; -import org.apache.plc4x.java.spi.generation.WriteBufferXmlBased; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class s7IoTest { - - @Disabled("Till the output is aligned to the one of golang") - @Test - void TestS7MessageBytes() throws Exception { - String wantXml = - "<TPKTPacket>\n" + - " <protocolId bitLength=\"8\" dataType=\"uint8\">3</protocolId>\n" + - " <reserved bitLength=\"8\" dataType=\"uint8\">0</reserved>\n" + - " <len bitLength=\"16\" dataType=\"uint16\">29</len>\n" + - " <COTPPacket>\n" + - " <headerLength bitLength=\"8\" dataType=\"uint18\">5</headerLength>\n" + - " <tpduCode bitLength=\"8\" dataType=\"uint8\">240</tpduCode>\n" + - " <COTPPacketData>\n" + - " <eot bitLength=\"1\" dataType=\"bit\">false</eot>\n" + - " <tpduRef bitLength=\"7\" dataType=\"uint8\">13</tpduRef>\n" + - " </COTPPacketData>\n" + - " <parameters>\n" + - " <COTPParameter>\n" + - " <parameterType bitLength=\"8\" dataType=\"uint8\">192</parameterType>\n" + - " <parameterLength bitLength=\"8\" dataType=\"uint8\">1</parameterLength>\n" + - " <COTPParameterTpduSize>\n" + - " <COTPTpduSize bitLength=\"8\" dataType=\"uint8\" stringRepresentation=\"SIZE_4096\">12</COTPTpduSize>\n" + - " </COTPParameterTpduSize>\n" + - " </COTPParameter>\n" + - " </parameters>\n" + - " <S7Message>\n" + - " <protocolId bitLength=\"8\" dataType=\"uint8\">50</protocolId>\n" + - " <messageType bitLength=\"8\" dataType=\"uint8\">3</messageType>\n" + - " <reserved bitLength=\"16\" dataType=\"uint16\">0</reserved>\n" + - " <tpduReference bitLength=\"16\" dataType=\"uint16\">11</tpduReference>\n" + - " <parameterLength bitLength=\"16\" dataType=\"uint16\">2</parameterLength>\n" + - " <payloadLength bitLength=\"16\" dataType=\"uint16\">5</payloadLength>\n" + - " <S7MessageResponseData>\n" + - " <errorClass bitLength=\"8\" dataType=\"uint8\">0</errorClass>\n" + - " <errorCode bitLength=\"8\" dataType=\"uint8\">0</errorCode>\n" + - " </S7MessageResponseData>\n" + - " <S7Parameter>\n" + - " <parameterType bitLength=\"8\" dataType=\"uint8\">4</parameterType>\n" + - " <S7ParameterReadVarResponse>\n" + - " <numItems bitLength=\"8\" dataType=\"uint8\">1</numItems>\n" + - " </S7ParameterReadVarResponse>\n" + - " </S7Parameter>\n" + - " <S7Payload>\n" + - " <S7PayloadReadVarResponse>\n" + - " <items>\n" + - " <S7VarPayloadDataItem>\n" + - " <DataTransportErrorCode bitLength=\"8\" dataType=\"uint8\" stringRepresentation=\"OK\">255</DataTransportErrorCode>\n" + - " <DataTransportSize bitLength=\"8\" dataType=\"uint8\" stringRepresentation=\"BIT\">3</DataTransportSize>\n" + - " <dataLength bitLength=\"16\" dataType=\"uint16\">1</dataLength>\n" + - " <data>\n" + - " <value bitLength=\"8\" dataType=\"int8\">1</value>\n" + - " </data>\n" + - " <padding></padding>\n" + - " </S7VarPayloadDataItem>\n" + - " </items>\n" + - " </S7PayloadReadVarResponse>\n" + - " </S7Payload>\n" + - " </S7Message>\n" + - " </COTPPacket>\n" + - "</TPKTPacket>"; - - - TPKTPacket tpktPacket = new TPKTPacket( - new COTPPacketData( - new COTPParameter[]{new COTPParameterTpduSize(COTPTpduSize.SIZE_4096)}, - new S7MessageResponseData( - 11, - new S7ParameterReadVarResponse((short) 1), - new S7PayloadReadVarResponse( - new S7VarPayloadDataItem[]{ - new S7VarPayloadDataItem( - DataTransportErrorCode.OK, - DataTransportSize.BIT, - new byte[]{0x1} - ) - } - ), - (short) 0, - (short) 0 - ), - false, - (short) 13 - ) - ); - WriteBufferXmlBased writeBufferXmlBased = new WriteBufferXmlBased(); - TPKTPacketIO.staticSerialize(writeBufferXmlBased, tpktPacket); - String gotXml = writeBufferXmlBased.getXmlString(); - assertEquals(wantXml,gotXml); - } -} diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java new file mode 100644 index 0000000..ec777b0 --- /dev/null +++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java @@ -0,0 +1,264 @@ +/* + 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.plc4x.java.spi.generation; + +import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.*; +import java.io.InputStream; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Iterator; + +public class ReadBufferXmlBased implements ReadBuffer { + + XMLEventReader reader; + + int pos = 1; + + public ReadBufferXmlBased(InputStream is) { + XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); + try { + reader = xmlInputFactory.createXMLEventReader(is); + } catch (XMLStreamException e) { + throw new PlcRuntimeException(e); + } + } + + @Override + public int getPos() { + return pos / 8; + } + + @Override + public boolean hasMore(int numBits) { + return true; + } + + @Override + public void pullContext(String logicalName) { + StartElement startElement = travelToNextStartElement(); + String elementName = startElement.getName().getLocalPart(); + if (!elementName.equals(logicalName)) { + throw new PlcRuntimeException(String.format("Unexpected Start element '%s'. Expected '%s'", elementName, logicalName)); + } + } + + @Override + public boolean readBit(String logicalName) throws ParseException { + String bit = decode(logicalName, "bit", 1); + move(1); + return bit.equals("1"); + } + + @Override + public byte readUnsignedByte(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Byte.parseByte(decode(logicalName, "uint8", bitLength)); + } + + @Override + public short readUnsignedShort(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Short.parseShort(decode(logicalName, "uint16", bitLength)); + } + + @Override + public int readUnsignedInt(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Integer.parseInt(decode(logicalName, "uint32", bitLength)); + } + + @Override + public long readUnsignedLong(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Long.parseLong(decode(logicalName, "uint32", bitLength)); + } + + @Override + public BigInteger readUnsignedBigInteger(String logicalName, int bitLength) throws ParseException { + move(bitLength); + throw new PlcRuntimeException("not implemented yet"); + } + + @Override + public byte readByte(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Byte.parseByte(decode(logicalName, "int8", bitLength)); + } + + @Override + public short readShort(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Short.parseShort(decode(logicalName, "int16", bitLength)); + } + + @Override + public int readInt(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Integer.parseInt(decode(logicalName, "int32", bitLength)); + } + + @Override + public long readLong(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Long.parseLong(decode(logicalName, "int64", bitLength)); + } + + @Override + public BigInteger readBigInteger(String logicalName, int bitLength) throws ParseException { + move(bitLength); + throw new PlcRuntimeException("not implemented yet"); + } + + @Override + public float readFloat(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Float.parseFloat(decode(logicalName, "float32", bitLength)); + } + + @Override + public double readDouble(String logicalName, int bitLength) throws ParseException { + move(bitLength); + return Double.parseDouble(decode(logicalName, "float64", bitLength)); + } + + @Override + public BigDecimal readBigDecimal(String logicalName, int bitLength) throws ParseException { + move(bitLength); + throw new PlcRuntimeException("not implemented yet"); + } + + @Override + public String readString(String logicalName, int bitLength, String encoding) { + move(bitLength); + return decode(logicalName, "string", bitLength); + } + + @Override + public void closeContext(String logicalName) { + EndElement endElement = travelToNextEndElement(); + if (!endElement.getName().getLocalPart().equals(logicalName)) { + throw new PlcRuntimeException(String.format("Unexpected End element '%s'. Expected '%s'", endElement.getName().getLocalPart(), logicalName)); + } + } + + private void move(int bits) { + pos += bits; + } + + private StartElement travelToNextStartElement() { + while (reader.hasNext()) { + XMLEvent xmlEvent; + try { + xmlEvent = reader.nextEvent(); + } catch (XMLStreamException e) { + throw new PlcRuntimeException(e); + } + if (xmlEvent.isStartElement()) { + return xmlEvent.asStartElement(); + } else if (xmlEvent.isEndElement()) { + throw new PlcRuntimeException(String.format("Unexpected End element %s", xmlEvent.asEndElement().getName().getLocalPart())); + } + } + throw new PlcRuntimeException("EOF"); + } + + private EndElement travelToNextEndElement() { + while (reader.hasNext()) { + XMLEvent xmlEvent; + try { + xmlEvent = reader.nextEvent(); + } catch (XMLStreamException e) { + throw new PlcRuntimeException(e); + } + if (xmlEvent.isStartElement()) { + throw new PlcRuntimeException("Unexpected Start element" + xmlEvent.asEndElement().getName().getLocalPart()); + } else if (xmlEvent.isEndElement()) { + return xmlEvent.asEndElement(); + } + } + throw new PlcRuntimeException("EOF"); + } + + private String decode(String logicalName, String dataType, int bitLength) { + StartElement startElement = travelToNextStartElement(); + validateStartElement(startElement, logicalName, dataType, bitLength); + Characters characters = null; + try { + characters = reader.nextEvent().asCharacters(); + } catch (XMLStreamException e) { + throw new PlcRuntimeException(e); + } + String data = characters.getData(); + try { + XMLEvent endEvent = reader.nextEvent().asEndElement(); + } catch (XMLStreamException e) { + throw new PlcRuntimeException(e); + } + return data; + } + + private boolean validateStartElement(StartElement startElement, String logicalName, String dataType, int bitLength) { + logicalName = sanitizeLogicalName(logicalName); + if (!startElement.getName().getLocalPart().equals(logicalName)) { + throw new PlcRuntimeException(String.format("unexpected element '%s'. Expected '%s'", startElement.getName().getLocalPart(), logicalName)); + } else if (!validateAttr(startElement.getAttributes(), dataType, bitLength)) { + throw new PlcRuntimeException("Error validating Attributes"); + } + return true; + } + + private boolean validateAttr(Iterator<Attribute> attr, String dataType, int bitLength) { + boolean dataTypeValidated = false; + boolean bitLengthValidate = false; + while (attr.hasNext()) { + Attribute attribute = attr.next(); + if (attribute.getName().getLocalPart().equals("dataType")) { + if (!attribute.getValue().equals(dataType)) { + throw new PlcRuntimeException(String.format("Unexpected dataType :%s. Want %s", attribute.getValue(), dataType)); + } + dataTypeValidated = true; + } else if (attribute.getName().getLocalPart().equals("bitLength")) { + if (!attribute.getValue().equals(Integer.valueOf(bitLength).toString())) { + throw new PlcRuntimeException(String.format("Unexpected bitLength '%s'. Want '%d'", attribute.getValue(), bitLength)); + } + bitLengthValidate = true; + } + } + if (!dataTypeValidated) { + throw new PlcRuntimeException("required attribute dataType missing"); + } + if (!bitLengthValidate) { + throw new PlcRuntimeException("required attribute bitLength missing"); + } + return true; + } + + private String sanitizeLogicalName(String logicalName) { + if (logicalName.equals("")) { + return "value"; + } + return logicalName; + } +} diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java index 6d32130..4b2b8b7 100644 --- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java +++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java @@ -42,6 +42,8 @@ public class WriteBufferXmlBased implements WriteBuffer { Document document; + int pos = 1; + public WriteBufferXmlBased() { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); try { @@ -54,7 +56,7 @@ public class WriteBufferXmlBased implements WriteBuffer { @Override public int getPos() { - return 0; + return pos/8; } @Override @@ -64,137 +66,97 @@ public class WriteBufferXmlBased implements WriteBuffer { @Override public void writeBit(String logicalName, boolean value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "bit"); - element.setAttribute("bitLength", "1"); - element.appendChild(document.createTextNode(Boolean.valueOf(value).toString())); - stack.peek().appendChild(element); + String dataType = "bit"; + int bitLength = 1; + String data = Boolean.valueOf(value).toString(); + createAndAppend(logicalName, dataType, bitLength, data); + move(1); } @Override public void writeUnsignedByte(String logicalName, int bitLength, byte value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "uint8"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Byte.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "uint8", bitLength, Byte.valueOf(value).toString()); + move(bitLength); } @Override public void writeUnsignedShort(String logicalName, int bitLength, short value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "uint16"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Short.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "uint16", bitLength, Short.valueOf(value).toString()); + move(bitLength); } @Override public void writeUnsignedInt(String logicalName, int bitLength, int value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "uint32"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Integer.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "uint32", bitLength, Integer.valueOf(value).toString()); + move(bitLength); } @Override public void writeUnsignedLong(String logicalName, int bitLength, long value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "uint64"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Long.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "uint64", bitLength, Long.valueOf(value).toString()); + move(bitLength); } @Override public void writeUnsignedBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "bigInt"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(value.toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "bigInt", bitLength, value.toString()); + move(bitLength); } @Override public void writeByte(String logicalName, int bitLength, byte value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "int8"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Byte.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "int8", bitLength, Byte.valueOf(value).toString()); + move(bitLength); } @Override public void writeShort(String logicalName, int bitLength, short value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "int16"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Short.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "int16", bitLength, Short.valueOf(value).toString()); + move(bitLength); } @Override public void writeInt(String logicalName, int bitLength, int value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "int32"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Integer.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "int32", bitLength, Integer.valueOf(value).toString()); + move(bitLength); } @Override public void writeLong(String logicalName, int bitLength, long value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "int64"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(Long.valueOf(value).toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "int64", bitLength, Long.valueOf(value).toString()); + move(bitLength); } @Override public void writeBigInteger(String logicalName, int bitLength, BigInteger value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "bigInt"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(value.toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "bigInt", bitLength, value.toString()); + move(bitLength); } @Override public void writeFloat(String logicalName, float value, int bitsExponent, int bitsMantissa) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "float32"); - element.setAttribute("bitLength", String.valueOf((value < 0 ? 1 : 0) + bitsExponent + bitsMantissa)); - element.appendChild(document.createTextNode(Float.valueOf(value).toString())); - stack.peek().appendChild(element); + int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa; + createAndAppend(logicalName, "float32", bitLength, Float.valueOf(value).toString()); + move(bitLength); } @Override public void writeDouble(String logicalName, double value, int bitsExponent, int bitsMantissa) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "float64"); - element.setAttribute("bitLength", String.valueOf((value < 0 ? 1 : 0) + bitsExponent + bitsMantissa)); - element.appendChild(document.createTextNode(Double.valueOf(value).toString())); - stack.peek().appendChild(element); + int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa; + createAndAppend(logicalName, "float64", bitLength, Double.valueOf(value).toString()); + move(bitLength); } @Override public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "bigFloat"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(value.toString())); - stack.peek().appendChild(element); + createAndAppend(logicalName, "bigFloat", bitLength, value.toString()); + move(bitLength); } @Override public void writeString(String logicalName, int bitLength, String encoding, String value) throws ParseException { - Element element = document.createElement(sanitizeLogicalName(logicalName)); - element.setAttribute("dataType", "string"); - element.setAttribute("bitLength", String.valueOf(bitLength)); - element.appendChild(document.createTextNode(value)); - stack.peek().appendChild(element); + createAndAppend(logicalName, "string", bitLength, value); + move(bitLength); } @Override @@ -230,6 +192,17 @@ public class WriteBufferXmlBased implements WriteBuffer { } } + private void move(int bits) { + pos += bits; + } + + private void createAndAppend(String logicalName, String dataType, int bitLength, String data) { + Element element = document.createElement(sanitizeLogicalName(logicalName)); + element.setAttribute("dataType", dataType); + element.setAttribute("bitLength", String.valueOf(bitLength)); + element.appendChild(document.createTextNode(data)); + stack.peek().appendChild(element); + } private String sanitizeLogicalName(String logicalName) { if (logicalName.equals("")) {
