| <#-- |
| 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. |
| --> |
| <#-- Prevent freemarker from escaping stuff --> |
| <#outputformat "undefined"> |
| <#-- Declare the name and type of variables passed in to the template --> |
| <#-- @ftlvariable name="languageName" type="java.lang.String" --> |
| <#-- @ftlvariable name="protocolName" type="java.lang.String" --> |
| <#-- @ftlvariable name="outputFlavor" type="java.lang.String" --> |
| <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" --> |
| <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" --> |
| <#-- Declare the name and type of variables declared locally inside the template --> |
| <#-- @ftlvariable name="typedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.TypedField" --> |
| <#-- @ftlvariable name="arrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField" --> |
| <#-- @ftlvariable name="checksumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ChecksumField" --> |
| <#-- @ftlvariable name="constField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ConstField" --> |
| <#-- @ftlvariable name="discriminatorField" type="org.apache.plc4x.plugins.codegenerator.types.fields.DiscriminatorField" --> |
| <#-- @ftlvariable name="enumField" type="org.apache.plc4x.plugins.codegenerator.types.fields.EnumField" --> |
| <#-- @ftlvariable name="implicitField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ImplicitField" --> |
| <#-- @ftlvariable name="manualArrayField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualArrayField" --> |
| <#-- @ftlvariable name="manualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ManualField" --> |
| <#-- @ftlvariable name="optionalField" type="org.apache.plc4x.plugins.codegenerator.types.fields.OptionalField" --> |
| <#-- @ftlvariable name="paddingField" type="org.apache.plc4x.plugins.codegenerator.types.fields.PaddingField" --> |
| <#-- @ftlvariable name="reservedField" type="org.apache.plc4x.plugins.codegenerator.types.fields.ReservedField" --> |
| <#-- @ftlvariable name="simpleField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SimpleField" --> |
| <#-- @ftlvariable name="switchField" type="org.apache.plc4x.plugins.codegenerator.types.fields.SwitchField" --> |
| <#-- @ftlvariable name="unknownField" type="org.apache.plc4x.plugins.codegenerator.types.fields.UnknownField" --> |
| <#-- @ftlvariable name="virtualField" type="org.apache.plc4x.plugins.codegenerator.types.fields.VirtualField" --> |
| <#-- @ftlvariable name="simpleTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.SimpleTypeReference" --> |
| <#-- @ftlvariable name="complexTypeReference" type="org.apache.plc4x.plugins.codegenerator.types.references.ComplexTypeReference" --> |
| ${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/io/${type.name}IO.java |
| /* |
| 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 ${helper.packageName(protocolName, languageName, outputFlavor)}.io; |
| |
| import static org.apache.plc4x.java.spi.generation.StaticHelper.*; |
| |
| import ${helper.packageName(protocolName, languageName, outputFlavor)}.*; |
| <#if helper.getComplexTypeReferences()?has_content>import ${helper.packageName(protocolName, languageName, outputFlavor)}.io.*;</#if> |
| import ${helper.packageName(protocolName, languageName, outputFlavor)}.types.*; |
| import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; |
| import org.apache.plc4x.java.spi.generation.*; |
| import org.apache.plc4x.java.api.value.PlcValue; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.math.BigInteger; |
| import java.time.*; |
| import java.util.*; |
| import java.util.function.Supplier; |
| |
| // Code generated by code-generation. DO NOT EDIT. |
| |
| public class ${type.name}IO implements <#if outputFlavor != "passive">MessageIO<${type.name}, ${type.name}><#else>MessageInput<${type.name}></#if> { |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(${type.name}IO.class); |
| |
| <#-- The parse and serialize methods here are just proxies for forwardning the requests to static counterparts --> |
| <#if !helper.isDiscriminatedChildTypeDefinition()> |
| @Override |
| public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException { |
| <#if type.parserArguments?has_content> |
| if((args == null) || (args.length != ${type.parserArguments?size})) { |
| throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length); |
| } |
| <#list type.parserArguments as parserArgument> |
| ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}; |
| if(args[${parserArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) { |
| ${parserArgument.name} = (${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}) args[${parserArgument?index}]; |
| <#if helper.isSimpleTypeReference(parserArgument.type)> |
| } else if (args[${parserArgument?index}] instanceof String) { |
| ${parserArgument.name} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}.valueOf((String) args[${parserArgument?index}]); |
| </#if> |
| } else { |
| throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} or a string which is parseable but was " + args[${parserArgument?index}].getClass().getName()); |
| } |
| </#list> |
| </#if> |
| return ${type.name}IO.staticParse(readBuffer<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>); |
| } |
| |
| <#if outputFlavor != "passive"> |
| @Override |
| public void serialize(WriteBuffer writeBuffer, ${type.name} value, Object... args) throws ParseException { |
| <#if helper.getSerializerArguments(type.parserArguments)?has_content> |
| if((args == null) || (args.length != ${type.parserArguments?size})) { |
| throw new PlcRuntimeException("Wrong number of arguments, expected ${type.parserArguments?size}, but got " + args.length); |
| } |
| <#list helper.getSerializerArguments(type.parserArguments) as serializerArgument> |
| if(!(args[${serializerArgument?index}] instanceof ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)})) { |
| throw new PlcRuntimeException("Argument ${serializerArgument?index} expected to be of type ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} but was " + args[${serializerArgument?index}].getClass().getName()); |
| } |
| ${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)} ${serializerArgument.name} = (${helper.getLanguageTypeNameForTypeReference(serializerArgument.type, false)}) args[${serializerArgument?index}]; |
| </#list> |
| </#if> |
| ${type.name}IO.staticSerialize(writeBuffer, value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>); |
| } |
| |
| </#if> |
| <#else> |
| @Override |
| public ${type.name} parse(ReadBuffer readBuffer, Object... args) throws ParseException { |
| return (${type.name}) new ${type.parentType.name}IO().parse(readBuffer, args); |
| } |
| |
| <#if outputFlavor != "passive"> |
| @Override |
| public void serialize(WriteBuffer writeBuffer, ${type.name} value, Object... args) throws ParseException { |
| new ${type.parentType.name}IO().serialize(writeBuffer, value, args); |
| } |
| |
| </#if> |
| </#if> |
| <#-- Here come the actual parse and serialize methods that actually do the parsing and serlaizing --> |
| public static ${type.name}<#if helper.isDiscriminatedChildTypeDefinition()>Builder</#if> staticParse(ReadBuffer readBuffer<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException { |
| readBuffer.pullContext("${type.name}"); |
| int startPos = readBuffer.getPos(); |
| int curPos; |
| <#list type.fields as field> |
| <#switch field.typeName> |
| <#case "array"> |
| <#assign arrayField = field> |
| <#if helper.isByteBased(arrayField.type)> |
| // Byte Array field (${arrayField.name}) |
| <#assign numberOfBytesExpression> |
| <#compress> |
| <#if helper.isCountArrayField(field)> |
| int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}; |
| <#elseif helper.isLengthArrayField(field)> |
| int numberOfBytes = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}; |
| <#elseif helper.isTerminatedArrayField(field)> |
| <#-- TODO: we need to find out to implement this--> |
| int numberOfBytes := ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}; |
| <#else> |
| <#-- TODO: we should throw a exception here--> |
| int numberOfBytes := -1 |
| </#if> |
| </#compress> |
| </#assign> |
| ${numberOfBytesExpression} |
| byte[] ${arrayField.name} = readBuffer.readByteArray("${arrayField.name}", numberOfBytes); |
| <#else> |
| // Array field (${arrayField.name}) |
| readBuffer.pullContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| <#-- Only update curPos if the length expression uses it --> |
| <#if arrayField.loopExpression.contains("curPos")> |
| curPos = readBuffer.getPos() - startPos; |
| </#if> |
| <#-- If this is a count array, we can directly initialize an array with the given size --> |
| <#if helper.isCountArrayField(field)> |
| // Count array |
| if(${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)} > Integer.MAX_VALUE) { |
| throw new ParseException("Array count of " + (${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}) + " exceeds the maximum allowed count of " + Integer.MAX_VALUE); |
| } |
| ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name}; |
| { |
| int itemCount = Math.max(0, (int) ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}); |
| ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[itemCount]; |
| for(int curItem = 0; curItem < itemCount; curItem++) { |
| <#-- When parsing simple types, there is nothing that could require the "lastItem" --> |
| <#if !helper.isSimpleTypeReference(arrayField.type)>boolean lastItem = curItem == (itemCount - 1);</#if> |
| <@compress single_line=true> |
| ${arrayField.name}[curItem] = |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| <#assign simpleTypeReference = arrayField.type> |
| ${helper.getReadBufferReadMethodCall("", simpleTypeReference, "", arrayField)} |
| <#else> |
| ${arrayField.type.name}IO.staticParse(readBuffer |
| <#if field.params?has_content> |
| , |
| <#list field.params as parserArgument> |
| <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true) = 'String'> |
| ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}.valueOf(${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep> |
| <#else> |
| (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep> |
| </#if> |
| </#list> |
| </#if>) |
| <#if helper.isDiscriminatedChildTypeDefinition(helper.getTypeDefinitionForTypeReference(arrayField.type))> |
| .build() |
| </#if> |
| </#if>; |
| </@compress> |
| } |
| } |
| <#-- In all other cases do we have to work with a list, that is later converted to an array --> |
| <#else> |
| <#-- For a length array, we read data till the read position of the buffer reaches a given position --> |
| <#if helper.isLengthArrayField(field)> |
| // Length array |
| int _${arrayField.name}Length = ${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}; |
| List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>(); |
| int ${arrayField.name}EndPos = readBuffer.getPos() + _${arrayField.name}Length; |
| while(readBuffer.getPos() < ${arrayField.name}EndPos) { |
| _${arrayField.name}List.add(<#if helper.isSimpleTypeReference(arrayField.type)><#assign simpleTypeReference = arrayField.type>${helper.getReadBufferReadMethodCall("", simpleTypeReference, "", arrayField)}<#else>${arrayField.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>); |
| <#-- After parsing, update the current position, but only if it's needed --> |
| <#if arrayField.loopExpression.contains("curPos")> |
| curPos = readBuffer.getPos() - startPos; |
| </#if> |
| } |
| <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false --> |
| <#elseif helper.isTerminatedArrayField(field)> |
| // Terminated array |
| List<${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}> _${arrayField.name}List = new LinkedList<>(); |
| while(!((boolean) (${helper.toParseExpression(arrayField, arrayField.loopExpression, type.parserArguments)}))) { |
| _${arrayField.name}List.add(<#if helper.isSimpleTypeReference(arrayField.type)><#assign simpleTypeReference = arrayField.type>${helper.getReadBufferReadMethodCall("", simpleTypeReference, "", arrayField)}<#else>${arrayField.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(arrayField.type, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>); |
| |
| <#-- After parsing, update the current position, but only if it's needed --> |
| <#if arrayField.loopExpression.contains("curPos")> |
| curPos = readBuffer.getPos() - startPos; |
| </#if> |
| } |
| </#if> |
| <#-- |
| Convert the list into an array. However if the array is of a primitive |
| type we have to iterate over it's elements and explicitly cast them. |
| Otherwise a simple toArray call is fine. |
| --> |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${arrayField.name}List.size()]; |
| for(int i = 0; i < _${arrayField.name}List.size(); i++) { |
| ${arrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${arrayField.name}List.get(i); |
| } |
| <#else> |
| ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = _${arrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]); |
| </#if> |
| </#if> |
| readBuffer.closeContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| </#if> |
| <#break> |
| <#case "checksum"> |
| <#assign checksumField = field> |
| <#assign simpleTypeReference = checksumField.type> |
| |
| // Checksum Field (checksum) |
| { |
| ${helper.getLanguageTypeNameForField(field)} checksum = ${helper.getNullValueForTypeReference(checksumField.type)}; |
| ${helper.getLanguageTypeNameForField(field)} checksumRef = ${helper.getReadBufferReadMethodCall("checksum", simpleTypeReference, "", checksumField)}; |
| checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.checksumExpression, type.parserArguments)}); |
| if(checksum != checksumRef) { |
| throw new ParseException(String.format("Checksum verification failed. Expected %04X but got %04X", checksumRef & 0xFFFF, checksum & 0xFFFF)); |
| } |
| } |
| <#break> |
| <#case "const"> |
| <#assign constField = field> |
| <#assign simpleTypeReference = constField.type> |
| |
| // Const Field (${constField.name}) |
| ${helper.getLanguageTypeNameForField(field)} ${constField.name} = ${helper.getReadBufferReadMethodCall(constField.name, simpleTypeReference, "", constField)}; |
| if(${constField.name} != ${type.name}.${constField.name?upper_case}) { |
| throw new ParseException("Expected constant value " + ${type.name}.${constField.name?upper_case} + " but got " + ${constField.name}); |
| } |
| <#break> |
| <#case "discriminator"> |
| <#assign discriminatorField = field> |
| |
| // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field) |
| <#if helper.isEnumField(field)> |
| ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = ${helper.getLanguageTypeNameForField(discriminatorField)}.enumForValue(${helper.getReadBufferReadMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "", discriminatorField)}); |
| <#else> |
| ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = <#if helper.isSimpleTypeReference(discriminatorField.type)>${helper.getReadBufferReadMethodCall(discriminatorField.name, discriminatorField.type, "", discriminatorField)}<#else>${discriminatorField.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(discriminatorField.type, parserArgument?index), true)}) (${helper.toParseExpression(discriminatorField, parserArgument, type)})<#sep>, </#sep></#list></#if>)</#if>; |
| </#if> |
| |
| <#break> |
| <#case "enum"> |
| <#assign enumField = field> |
| |
| readBuffer.pullContext("${enumField.name}"); |
| // Enum field (${enumField.name}) |
| <#if enumField.fieldName?has_content> |
| ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.firstEnumForField${enumField.fieldName?cap_first}(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)}); |
| <#else> |
| ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = ${helper.getLanguageTypeNameForField(field)}.enumForValue(${helper.getReadBufferReadMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "", enumField)}); |
| </#if> |
| readBuffer.closeContext("${enumField.name}"); |
| <#break> |
| <#case "implicit"> |
| <#assign implicitField = field> |
| <#assign simpleTypeReference = implicitField.type> |
| |
| // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content) |
| ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = ${helper.getReadBufferReadMethodCall(implicitField.name, simpleTypeReference, "", implicitField)}; |
| <#break> |
| <#case "manualArray"> |
| <#assign manualArrayField = field> |
| |
| readBuffer.pullContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| // Manual Array Field (${manualArrayField.name}) |
| <#-- Only update curPos if the length expression uses it --> |
| <#if manualArrayField.loopExpression.contains("curPos")> |
| curPos = readBuffer.getPos() - startPos; |
| </#if> |
| <#-- If this is a count array, we can directly initialize an array with the given size --> |
| <#if helper.isCountArrayField(field)> |
| // Count array |
| int _${manualArrayField.name}Count = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)}; |
| ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}Count]; |
| for(int i = 0; i < _${manualArrayField.name}Count; i++) { |
| ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)}); |
| } |
| <#-- In all other cases do we have to work with a list, that is later converted to an array --> |
| <#else> |
| <#-- For a length array, we read data till the read position of the buffer reaches a given position --> |
| <#if helper.isLengthArrayField(field)> |
| // Length array |
| int _${manualArrayField.name}Length = ${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)}; |
| List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>(); |
| int ${manualArrayField.name}EndPos = readBuffer.getPos() + _${manualArrayField.name}Length; |
| while(readBuffer.getPos() < ${manualArrayField.name}EndPos) { |
| _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)})); |
| <#-- After parsing, update the current position, but only if it's needed --> |
| <#if manualArrayField.loopExpression.contains("curPos")> |
| curPos = readBuffer.getPos() - startPos; |
| </#if> |
| } |
| <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false --> |
| <#elseif helper.isTerminatedArrayField(field)> |
| // Terminated array |
| List<${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}> _${manualArrayField.name}List = new LinkedList<>(); |
| while(!((boolean) (${helper.toParseExpression(manualArrayField, manualArrayField.loopExpression, type.parserArguments)}))) { |
| _${manualArrayField.name}List.add((${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualArrayField, manualArrayField.parseExpression, type.parserArguments)})); |
| |
| <#-- After parsing, update the current position, but only if it's needed --> |
| <#if manualArrayField.loopExpression.contains("curPos")> |
| curPos = readBuffer.getPos() - startPos; |
| </#if> |
| } |
| </#if> |
| <#-- |
| Convert the list into an array. However if the array is of a primitive |
| type we have to iterate over it's elements and explicitly cast them. |
| Otherwise a simple toArray call is fine. |
| --> |
| <#if helper.isSimpleTypeReference(field.type)> |
| ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = new ${helper.getLanguageTypeNameForField(field)}[_${manualArrayField.name}List.size()]; |
| for(int i = 0; i < _${manualArrayField.name}List.size(); i++) { |
| ${manualArrayField.name}[i] = (${helper.getLanguageTypeNameForField(field)}) _${manualArrayField.name}List.get(i); |
| } |
| <#else> |
| ${helper.getLanguageTypeNameForField(field)}[] ${manualArrayField.name} = _${manualArrayField.name}List.toArray(new ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)}[0]); |
| </#if> |
| </#if> |
| readBuffer.closeContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| <#break> |
| <#case "manual"> |
| <#assign manualField = field> |
| |
| // Manual Field (${manualField.name}) |
| ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(manualField, manualField.parseExpression, type.parserArguments)}); |
| <#break> |
| <#case "optional"> |
| <#assign optionalField = field> |
| |
| // Optional Field (${optionalField.name}) (Can be skipped, if a given expression evaluates to false) |
| <#if optionalField.conditionExpression.contains("curPos")> |
| curPos = readBuffer.getPos() - startPos; |
| </#if> |
| ${helper.getLanguageTypeNameForField(field)} ${optionalField.name} = null; |
| if(${helper.toParseExpression(optionalField, optionalField.conditionExpression, type.parserArguments)}) { |
| <#if helper.isEnumField(field)> |
| ${optionalField.name} = ${helper.getLanguageTypeNameForField(optionalField)}.enumForValue(${helper.getReadBufferReadMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "", optionalField)}); |
| <#else> |
| ${optionalField.name} = <#if helper.isSimpleTypeReference(optionalField.type)>${helper.getReadBufferReadMethodCall(optionalField.name, optionalField.type, "", optionalField)}<#else>${optionalField.type.name}IO.staticParse(readBuffer<#if field.params?has_content>, <#list field.params as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(optionalField.type, parserArgument?index), true)}) (${helper.toParseExpression(optionalField, parserArgument, type.parserArguments)})<#sep>, </#sep></#list></#if>)</#if>; |
| </#if> |
| } |
| <#break> |
| <#case "padding"> |
| <#assign paddingField = field> |
| <#assign simpleTypeReference = paddingField.type> |
| |
| // Padding Field (padding) |
| { |
| readBuffer.pullContext("padding", WithReaderWriterArgs.WithRenderAsList(true)); |
| int _timesPadding = (int) (${helper.toParseExpression(paddingField, paddingField.paddingCondition, type.parserArguments)}); |
| while ((readBuffer.hasMore(${helper.getNumBits(simpleTypeReference)})) && (_timesPadding-- > 0)) { |
| // Just read the padding data and ignore it |
| ${helper.getReadBufferReadMethodCall(simpleTypeReference, "", paddingField)}; |
| } |
| readBuffer.closeContext("padding", WithReaderWriterArgs.WithRenderAsList(true)); |
| } |
| <#break> |
| <#case "reserved"> |
| <#assign reservedField = field> |
| <#assign simpleTypeReference = reservedField.type> |
| |
| // Reserved Field (Compartmentalized so the "reserved" variable can't leak) |
| { |
| ${helper.getLanguageTypeNameForField(field)} reserved = ${helper.getReadBufferReadMethodCall("reserved", simpleTypeReference, "", reservedField)}; |
| if(reserved != ${helper.getReservedValue(reservedField)}) { |
| LOGGER.info("Expected constant value " + ${reservedField.referenceValue} + " but got " + reserved + " for reserved field."); |
| } |
| } |
| <#break> |
| <#case "simple"> |
| <#assign simpleField = field> |
| |
| <#if !helper.isSimpleTypeReference(simpleField.type)> |
| readBuffer.pullContext("${simpleField.name}"); |
| </#if> |
| |
| // Simple Field (${simpleField.name}) |
| <#if helper.isEnumField(field)> |
| // enum based simple field with type ${simpleField.type.name} |
| ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = ${helper.getLanguageTypeNameForField(simpleField)}.enumForValue(${helper.getReadBufferReadMethodCall(simpleField.type.name, helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)}); |
| <#else> |
| <#assign simpleFieldLogicalName><#if helper.isSimpleTypeReference(simpleField.type)>${simpleField.name}<#else>${simpleField.typeName}</#if></#assign> |
| <@compress single_line=true> |
| ${helper.getLanguageTypeNameForField(simpleField)} ${simpleField.name} = |
| <#if helper.isSimpleTypeReference(simpleField.type)> |
| <#assign simpleTypeReference = simpleField.type> |
| ${helper.getReadBufferReadMethodCall(simpleFieldLogicalName, simpleTypeReference, "", simpleField)} |
| <#else> |
| <#assign complexTypeReference = simpleField.type> |
| ${complexTypeReference.name}IO.staticParse(readBuffer |
| <#if field.params?has_content> |
| , |
| <#list field.params as parserArgument> |
| <#if helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleField.type, parserArgument?index), true) = 'String'> |
| ${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleField.type, parserArgument?index), true)}.valueOf(${helper.toParseExpression(simpleField, parserArgument, type.parserArguments)})<#sep>, </#sep> |
| <#else> |
| (${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleField.type, parserArgument?index), true)}) (${helper.toParseExpression(simpleField, parserArgument, type.parserArguments)})<#sep>, </#sep> |
| </#if> |
| </#list> |
| </#if>) |
| </#if>; |
| </@compress> |
| </#if> |
| <#if !helper.isSimpleTypeReference(simpleField.type)> |
| readBuffer.closeContext("${simpleField.name}"); |
| </#if> |
| <#break> |
| <#case "switch"> |
| <#assign switchField = field> |
| |
| // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type) |
| ${type.name}Builder builder = null; |
| <#list switchField.cases as case> |
| <#if case.discriminatorValues?has_content>if(<#list case.discriminatorValues as discriminatorValue>EvaluationHelper.equals(${helper.toParseExpression(null, switchField.discriminatorExpressions[discriminatorValue?index], type.parserArguments)}, <#if helper.discriminatorValueNeedsStringEqualityCheck(switchField.discriminatorExpressions[discriminatorValue?index])>"${discriminatorValue}"<#elseif helper.isComplexTypeReference(helper.getDiscriminatorTypes()[field.discriminatorExpressions[discriminatorValue?index].name])><#if helper.isEnumTypeReference(helper.getDiscriminatorTypes()[field.discriminatorExpressions[discriminatorValue?index].name])>${helper.getDiscriminatorTypes()[field.discriminatorExpressions[discriminatorValue?index].name].name}.${discriminatorValue}<#else>${discriminatorValue}</#if><#else>${discriminatorValue}</#if>)<#sep> && </#sep></#list>) </#if>{ |
| builder = ${case.name}IO.staticParse(readBuffer<#if case.parserArguments?has_content>, <#list case.parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>); |
| }<#sep> else </#sep> |
| </#list> |
| if (builder == null) { |
| throw new ParseException("Unsupported case for discriminated type"); |
| } |
| <#break> |
| |
| <#case "unknown"> |
| <#assign unknownField = field> |
| <#assign simpleTypeReference = unknownField.type> |
| |
| // Unknown Field |
| ${helper.getReadBufferReadMethodCall("unknown" , simpleTypeReference, "", unknownField)}; |
| <#break> |
| |
| <#case "virtual"> |
| <#assign virtualField = field> |
| |
| // Virtual field (Just declare a local variable so we can access it in the parser) |
| <#if helper.getLanguageTypeNameForField(field) = 'String'> |
| ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toParseExpression(virtualField, virtualField.valueExpression, type.parserArguments)}); |
| <#else> |
| ${helper.getLanguageTypeNameForField(field)} ${virtualField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(virtualField, virtualField.valueExpression, type.parserArguments)}); |
| </#if> |
| <#break> |
| </#switch> |
| </#list> |
| |
| readBuffer.closeContext("${type.name}"); |
| // Create the instance |
| <#if helper.isDiscriminatedChildTypeDefinition()> |
| return new ${type.name}Builder(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>); |
| <#elseif helper.isDiscriminatedParentTypeDefinition()> |
| return builder.build(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>); |
| <#else> |
| return new ${type.name}(<#list type.propertyFields as field>${field.name}<#sep>, </#sep></#list>); |
| </#if> |
| } |
| |
| <#if outputFlavor != "passive"> |
| public static void staticSerialize(WriteBuffer writeBuffer, ${type.name} _value<#if helper.getSerializerArguments(type.parserArguments)?has_content>, <#list helper.getSerializerArguments(type.parserArguments) as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException { |
| <#if helper.hasFieldOfType("unknown")> |
| throw new ParseException("Unknown field not serializable"); |
| <#else> |
| int startPos = writeBuffer.getPos(); |
| writeBuffer.pushContext("${type.name}"); |
| <#list type.fields as field> |
| <#switch field.typeName> |
| <#case "array"> |
| <#assign arrayField = field> |
| <#assign simpleTypeReference = arrayField.type> |
| |
| // Array Field (${arrayField.name}) |
| if(_value.get${arrayField.name?cap_first}() != null) { |
| <#if helper.isByteBased(arrayField.type)> |
| // Byte Array field (${arrayField.name}) |
| writeBuffer.writeByteArray("${arrayField.name}", _value.get${arrayField.name?cap_first}()); |
| <#else> |
| writeBuffer.pushContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| int itemCount = (int) _value.get${arrayField.name?cap_first}().length; |
| int curItem = 0; |
| for(${helper.getLanguageTypeNameForField(field)} element : _value.get${arrayField.name?cap_first}()) { |
| <#if helper.isSimpleTypeReference(arrayField.type)> |
| <#assign simpleTypeReference = arrayField.type> |
| ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "element", field)}; |
| <#else> |
| <#assign complexTypeReference = arrayField.type> |
| boolean lastItem = curItem == (itemCount - 1); |
| ${complexTypeReference.name}IO.staticSerialize(writeBuffer, element<#if helper.getSerializerTerms(field.params)?has_content>, <#list helper.getSerializerTerms(field.params) as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>); |
| </#if> |
| curItem++; |
| } |
| writeBuffer.popContext("${arrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| </#if> |
| } |
| <#break> |
| <#case "checksum"> |
| <#assign checksumField = field> |
| <#assign simpleTypeReference = checksumField.type> |
| |
| // Checksum Field (checksum) (Calculated) |
| { |
| ${helper.getLanguageTypeNameForField(field)} _checksum = ${helper.getNullValueForTypeReference(checksumField.type)}; |
| _checksum = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(checksumField, checksumField.checksumExpression, type.parserArguments)}); |
| ${helper.getWriteBufferWriteMethodCall("checksum", simpleTypeReference, "(_checksum)", field)}; |
| } |
| <#break> |
| <#case "const"> |
| <#assign constField = field> |
| <#assign simpleTypeReference = constField.type> |
| |
| // Const Field (${constField.name}) |
| <#if helper.getLanguageTypeNameForField(field) = 'float'>${helper.getWriteBufferWriteMethodCall(simpleTypeReference, constField.referenceValue + "f", field)}; |
| <#else>${helper.getWriteBufferWriteMethodCall(constField.name, simpleTypeReference, constField.referenceValue, field)}; |
| </#if> |
| <#break> |
| <#case "discriminator"> |
| <#assign discriminatorField = field> |
| |
| // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field) |
| ${helper.getLanguageTypeNameForField(field)} ${discriminatorField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${discriminatorField.name?cap_first}(); |
| <#if helper.isSimpleTypeReference(discriminatorField.type)> |
| <#assign simpleTypeReference = discriminatorField.type> |
| ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, simpleTypeReference, "(" + discriminatorField.name + ")", field)}; |
| <#else> |
| <#assign complexTypeReference = discriminatorField.type> |
| <#if helper.isEnumField(field)> |
| ${helper.getWriteBufferWriteMethodCall(discriminatorField.name, helper.getEnumBaseTypeReference(discriminatorField.type), "(" + discriminatorField.name + ".getValue())", field)}; |
| <#else> |
| ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${discriminatorField.name}); |
| </#if> |
| </#if> |
| <#break> |
| <#case "enum"> |
| <#assign enumField = field> |
| |
| writeBuffer.pushContext("${enumField.name}"); |
| // Enum field (${enumField.name}) |
| ${helper.getLanguageTypeNameForField(field)} ${enumField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${enumField.name?cap_first}(); |
| <#if enumField.fieldName?has_content> |
| ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumFieldSimpleTypeReference(enumField.type, enumField.fieldName), "(" + enumField.name + ".get" + enumField.fieldName?cap_first + "())", field, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")}; |
| <#else> |
| ${helper.getWriteBufferWriteMethodCall(helper.getTypeDefinitionForTypeReference(enumField.type).name, helper.getEnumBaseTypeReference(enumField.type), "(" + enumField.name + ".getValue())", field, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${enumField.name}.name())")}; |
| </#if> |
| writeBuffer.popContext("${enumField.name}"); |
| <#break> |
| <#case "implicit"> |
| <#assign implicitField = field> |
| <#assign simpleTypeReference = implicitField.type> |
| |
| // Implicit Field (${implicitField.name}) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content) |
| ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.serializeExpression, type.parserArguments)}); |
| ${helper.getWriteBufferWriteMethodCall(implicitField.name, simpleTypeReference, "(" + implicitField.name + ")", field)}; |
| <#break> |
| <#case "manualArray"> |
| <#assign manualArrayField = field> |
| |
| // Manual Array Field (${manualArrayField.name}) |
| if(_value.get${manualArrayField.name?cap_first}() != null) { |
| writeBuffer.pushContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| for(${helper.getLanguageTypeNameForField(field)} element : _value.get${manualArrayField.name?cap_first}()) { |
| ${helper.toSerializationExpression(manualArrayField, manualArrayField.serializeExpression, type.parserArguments)}; |
| } |
| writeBuffer.popContext("${manualArrayField.name}", WithReaderWriterArgs.WithRenderAsList(true)); |
| } |
| <#break> |
| <#case "manual"> |
| <#assign manualField = field> |
| |
| // Manual Field (${manualField.name}) |
| ${helper.toSerializationExpression(manualField, manualField.serializeExpression, type.parserArguments)}; |
| <#break> |
| <#case "optional"> |
| <#assign optionalField = field> |
| |
| // Optional Field (${optionalField.name}) (Can be skipped, if the value is null) |
| ${helper.getLanguageTypeNameForField(field)} ${optionalField.name} = null; |
| if(_value.get${optionalField.name?cap_first}() != null) { |
| ${optionalField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${optionalField.name?cap_first}(); |
| <#if helper.isSimpleTypeReference(optionalField.type)> |
| <#assign simpleTypeReference = optionalField.type> |
| ${helper.getWriteBufferWriteMethodCall(optionalField.name, simpleTypeReference, "(" + optionalField.name + ")", field)}; |
| <#else> |
| <#assign complexTypeReference = optionalField.type> |
| <#if helper.isEnumField(field)> |
| ${helper.getWriteBufferWriteMethodCall(optionalField.name, helper.getEnumBaseTypeReference(optionalField.type), "(" + optionalField.name + ".getValue())", field)}; |
| <#else> |
| ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${optionalField.name}); |
| </#if> |
| </#if> |
| } |
| <#break> |
| <#case "padding"> |
| <#assign paddingField = field> |
| <#assign simpleTypeReference = paddingField.type> |
| |
| // Padding Field (padding) |
| { |
| writeBuffer.pushContext("padding", WithReaderWriterArgs.WithRenderAsList(true)); |
| int _timesPadding = (int) (${helper.toSerializationExpression(paddingField, paddingField.paddingCondition, type.parserArguments)}); |
| while (_timesPadding-- > 0) { |
| ${helper.getLanguageTypeNameForField(field)} _paddingValue = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(paddingField, paddingField.paddingValue, type.parserArguments)}); |
| ${helper.getWriteBufferWriteMethodCall("", simpleTypeReference, "(_paddingValue)", field)}; |
| } |
| writeBuffer.popContext("padding", WithReaderWriterArgs.WithRenderAsList(true)); |
| } |
| <#break> |
| <#case "reserved"> |
| <#assign reservedField = field> |
| <#assign simpleTypeReference = reservedField.type> |
| |
| // Reserved Field (reserved) |
| ${helper.getWriteBufferWriteMethodCall("reserved", simpleTypeReference, helper.getReservedValue(field), field)}; |
| <#break> |
| <#case "simple"> |
| <#assign simpleField = field> |
| |
| // Simple Field (${simpleField.name}) |
| ${helper.getLanguageTypeNameForField(field)} ${simpleField.name} = (${helper.getLanguageTypeNameForField(field)}) _value.get${simpleField.name?cap_first}(); |
| <#if helper.isSimpleTypeReference(simpleField.type)> |
| <#assign simpleTypeReference = simpleField.type> |
| <#if helper.isEnumField(field)> |
| // enum based simple field with type ${simpleField.type.name} |
| ${helper.getWriteBufferWriteMethodCall(simpleField.type.name, simpleTypeReference, "(" + simpleField.name + ")", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")}; |
| <#else> |
| ${helper.getWriteBufferWriteMethodCall(simpleField.name, simpleTypeReference, "(" + simpleField.name + ")", simpleField)}; |
| </#if> |
| <#else> |
| writeBuffer.pushContext("${simpleField.name}"); |
| <#assign complexTypeReference = simpleField.type> |
| <#if helper.isEnumField(field)> |
| // enum field with type ${simpleField.type.name} |
| ${helper.getWriteBufferWriteMethodCall(simpleField.type.name, helper.getEnumBaseTypeReference(simpleField.type), "(" + simpleField.name + ".getValue())", simpleField, "WithReaderWriterArgs.WithAdditionalStringRepresentation(${simpleField.name}.name())")}; |
| <#else> |
| ${complexTypeReference.name}IO.staticSerialize(writeBuffer, ${simpleField.name}); |
| </#if> |
| writeBuffer.popContext("${simpleField.name}"); |
| </#if> |
| <#break> |
| <#case "switch"> |
| <#assign switchField = field> |
| |
| // Switch field (Depending on the discriminator values, passes the instantiation to a sub-type) |
| <#list switchField.cases as case> |
| if(_value instanceof ${case.name}) { |
| ${case.name}IO.staticSerialize(writeBuffer, (${case.name}) _value); |
| }<#sep> else </#sep> |
| </#list> |
| <#break> |
| <#case "virtual"> |
| <#break> |
| </#switch> |
| </#list> |
| writeBuffer.popContext("${type.name}"); |
| </#if> |
| } |
| </#if> |
| |
| <#if helper.isDiscriminatedParentTypeDefinition()> |
| public static interface ${type.name}Builder { |
| ${type.name} build(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>); |
| } |
| |
| </#if> |
| <#if helper.isDiscriminatedChildTypeDefinition()> |
| public static class ${type.name}Builder implements ${type.parentType.name}IO.${type.parentType.name}Builder { |
| <#if type.propertyFields?has_content> |
| <#list type.propertyFields as field> |
| private final ${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}; |
| </#list> |
| </#if> |
| |
| public ${type.name}Builder(<#list type.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) { |
| <#list type.propertyFields as field> |
| this.${field.name} = ${field.name}; |
| </#list> |
| } |
| |
| public ${type.name} build(<#list type.parentType.propertyFields as field>${helper.getLanguageTypeNameForField(field)}<#if field.loopType??>[]</#if> ${field.name}<#sep>, </#sep></#list>) { |
| return new ${type.name}(<#list type.getAllPropertyFields() as field>${field.name}<#sep>, </#sep></#list>); |
| } |
| } |
| |
| </#if> |
| } |
| </#outputformat> |