/* Protocol Definition Language Copyright (C) 2003-2006 Marcus Andersson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package net.sf.nmedit.jpdl; import java.util.*; public class PacketParser { public PacketParser(String name, int padding, Protocol protocol) { this.name = name; this.padding = padding; this.protocol = protocol; this.totalMinimumSize = 0; } public boolean parse(BitStream data, Packet result) { return parse(data, result, 0); } public boolean parse(BitStream data, Packet result, int reserved) { boolean conditional = false; boolean conditionalMatch = false; int dataPos = data.getPosition(); if (protocol.isTraceEnabled()) { protocol.trace("PARSE PACKET " + name); } result.setName(name); int minimumSize = totalMinimumSize + reserved; for (Matcher matcher: matchers) { minimumSize -= matcher.minimumSize(); if (matcher.isConditional()) { conditional = true; if (matcher.trueCondition(result)) { boolean success = matcher.match(protocol, data, result, minimumSize); if (success) { conditionalMatch = true; } } } else { boolean success = matcher.match(protocol, data, result, minimumSize); if (!success && !matcher.isOptional()) { if (protocol.isTraceEnabled()) { protocol.trace("FAILED " + name+"; "+matcher); } data.setPosition(dataPos); result.clear(); return false; } } } if (!conditional || (conditional && conditionalMatch)) { data.getInt(((data.getPosition()-dataPos) % padding) == 0 ? 0 : padding - ((data.getPosition()-dataPos) % padding)); if (protocol.isTraceEnabled()) { protocol.trace("MATCHED " + name); } return true; } if (protocol.isTraceEnabled()) { protocol.trace("FAILED " + name); } data.setPosition(dataPos); result.clear(); return false; } public boolean generate(IntStream data, BitStream result) { Packet packet = new Packet(); boolean conditional = false; boolean conditionalMatch = false; int dataPos = data.getPosition(); int resultSize = result.getSize(); if (protocol.isTraceEnabled()) { protocol.trace("GENERATE PACKET " + name); } for (Matcher matcher: matchers) { if (matcher.isConditional()) { conditional = true; if (matcher.trueCondition(packet)) { boolean success = matcher.apply(protocol, packet, data, result); if (success) { conditionalMatch = true; } } } else { boolean success = matcher.apply(protocol, packet, data, result); if (!success && !matcher.isOptional()) { if (protocol.isTraceEnabled()) { protocol.trace("FAILED " + name+"; "+matcher); } data.setPosition(dataPos); result.setSize(resultSize); return false; } } } if (!conditional || (conditional && conditionalMatch)) { result.append(0, ((result.getSize()-resultSize) % padding) == 0 ? 0 : padding - ((result.getSize()-resultSize) % padding)); if (protocol.isTraceEnabled()) { protocol.trace("MATCHED " + name); } return true; } if (protocol.isTraceEnabled()) { protocol.trace("FAILED " + name); } data.setPosition(dataPos); result.setSize(resultSize); return false; } public void addPacketMatcher(String count, String packetName, String binding, Condition condition, boolean optional) { matchers.add(new PacketMatcher(count, packetName, binding, condition, optional)); } public void addVariableMatcher(int count, String variable, int size, int terminal, Condition condition, boolean optional) { Matcher matcher = new VariableMatcher(count, variable, size, terminal, condition, optional); matchers.add(matcher); totalMinimumSize += matcher.minimumSize(); } public void addConstantMatcher(int constant, int size, Condition condition, boolean optional) { Matcher matcher = new ConstantMatcher(constant, size, condition, optional); matchers.add(matcher); totalMinimumSize += matcher.minimumSize(); } public String getName() { return name; } public List<Matcher> getMatchers() { return Collections.unmodifiableList(matchers); } private String name; private int padding; private Protocol protocol; private List<Matcher> matchers = new LinkedList<Matcher>(); private int totalMinimumSize; }