/*
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.jpdl2.utils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import net.sf.nmedit.jpdl2.PDLException;
import net.sf.nmedit.jpdl2.PDLPacket;
import net.sf.nmedit.jpdl2.dom.PDLBlock;
import net.sf.nmedit.jpdl2.dom.PDLItem;
import net.sf.nmedit.jpdl2.dom.PDLItemType;
import net.sf.nmedit.jpdl2.dom.PDLMultiplicity;
import net.sf.nmedit.jpdl2.dom.PDLPacketRef;
public class PDLUtils
{
public static String toHexadecimal( int[] b )
{
if (b.length == 0)
return "[]";
StringBuilder sb = new StringBuilder(b.length*3+1);
sb.append('[');
sb.append(Integer.toHexString(b[0]).toUpperCase());
for (int i=1;i<b.length;i++)
{
sb.append(' ');
sb.append(Integer.toHexString(b[i]).toUpperCase());
}
sb.append(']');
return sb.toString();
}
public static String toHexadecimal( byte[] b )
{
if (b.length == 0)
return "[]";
StringBuilder sb = new StringBuilder(b.length*3+1);
sb.append('[');
sb.append(toHexadecimal(b[0]));
for (int i=1;i<b.length;i++)
{
sb.append(' ');
sb.append(toHexadecimal(b[i]));
}
sb.append(']');
return sb.toString();
}
private static String toHexadecimal(byte b)
{
int unsignedbyte = (int)(b&0xFF);
return (unsignedbyte<=0xF ? "0" : "") + Integer.toHexString(unsignedbyte).toUpperCase();
}
private static void toString(PDLPacket packet, StringBuilder sb, final int depth)
{
sb.append(packet.getName());
if (packet.getBinding() != null)
sb.append("$"+packet.getBinding());
sb.append("{");
List<String> members;
int memberCount = 0;
members = packet.getAllVariables();
memberCount += members.size();
if (!members.isEmpty())
{
for (String variable: members) sb.append(variable+"="+packet.getVariable(variable)+";");
}
members = packet.getAllStrings();
memberCount += members.size();
if (!members.isEmpty())
{
for (String s: members)
{
sb.append(s+":=\""+packet.getString(s)+"\";");
}
}
members = packet.getAllVariableLists();
memberCount += members.size();
if (!members.isEmpty())
{
if (memberCount>1) sb.append("\n ");
for (String vlist: members) sb.append(variableListToString(vlist, packet)+";");
}
members = packet.getAllPacketLists();
memberCount += members.size();
if (!members.isEmpty())
{
if (memberCount>2) sb.append("\n ");
for (String plist: members)
{
sb.append(plist+"=[\n ");
PDLPacket[] list = packet.getPacketList(plist);
for (PDLPacket p: list)
toString(p, sb, depth+1);
sb.append("]\n");
}
}
members = packet.getAllPackets();
memberCount += members.size();
if (!members.isEmpty())
{
if (memberCount>2) sb.append("\n ");
for (String p: members)
{
toString(packet.getPacket(p), sb, depth+1);
}
}
sb.append("}");
if (memberCount>2)
sb.append("\n ");
}
private static String variableListToString(String vlist, PDLPacket packet)
{
String defaultResult = vlist+"[]";
int[] data = packet.getVariableList(vlist);
if (data.length<=16)
{
StringBuilder sb = new StringBuilder();
StringBuilder ints = new StringBuilder();
for (int i=0;i<data.length;i++)
{
if (!Character.isDefined((char)data[i]))
return defaultResult;
sb.append((char)data[i]);
if (i>0) ints.append(", ");
ints.append(Integer.toString(data[i]));
}
return "[\""+sb+"\"|"+ints+"]";
}
return defaultResult;
}
public static String toString(PDLPacket packet)
{
StringBuilder sb = new StringBuilder();
toString(packet, sb, 0);
return sb.toString();
}
public static int parseHex(String s)
{
if (s.length()<3 || s.charAt(0)!='0' || s.charAt(1)!='x')
throw new NumberFormatException("not a hexadecimal number: "+s);
int val = 0;
for (int i=2;i<s.length();i++)
{
val*=16;
char c = s.charAt(i);
if ('0'<=c && c<='9') val+=(c-'0');
else if ('a'<=c && c<='f') val+=(c-'a'+10);
else if ('A'<=c && c<='F') val+=(c-'A'+10);
else throw new NumberFormatException("not a hexadecimal number: "+s);
}
return val;
}
public static int parseDual(String s)
{
if (s.length()<2 || Character.toLowerCase(s.charAt(s.length()-1))!='d')
throw new NumberFormatException("not a dual number: "+s);
if (s.length()>33)
throw new NumberFormatException("number has more than 32 digits:"+s);
int val = 0;
for (int i=0;i<s.length()-1;i++)
{
val = val << 1;
switch(s.charAt(i))
{
case '1': val |= 1; break;
case '0': break;
default: throw new NumberFormatException("not a dual number: "+s);
}
}
return val;
}
public static void checkBitcount(int bitcount) throws PDLException
{
if (bitcount<0 || bitcount>32)
throw new PDLException("size must be in set [0,1,..,32]: "+bitcount);
}
public static void checkBounds(int value, int bitcount) throws PDLException
{
PDLUtils.checkBitcount(bitcount);
int mask = 0xFfFfFfFf >>> (32-bitcount);
if (value != (value&mask))
throw new PDLException("value requires more than "+bitcount+" bits: "+value);
}
public static String getBinding(PDLPacketRef packetReference)
{
String binding = packetReference.getBinding();
if (binding == null)
binding = packetReference.getPacketName();
return binding;
}
public static int getMinMultiplicity(PDLMultiplicity multiplicity)
{
if (multiplicity == null)
return 1;
if (multiplicity.getConstant()>=0)
return multiplicity.getConstant();
else
return 0;
}
public static int getMultiplicity(PDLPacket context, PDLMultiplicity multiplicity)
{
if (multiplicity == null)
return 1;
if (multiplicity.getConstant()>=0)
return multiplicity.getConstant();
else
return context.getVariable(multiplicity.getVariable());
}
public static <T extends PDLItem> Iterator<T> filter(final PDLItemType type, final Iterator<T> iter)
{
return new Iterator<T>()
{
T next = null;
private void align()
{
while (next == null && iter.hasNext())
{
T i = iter.next();
if (i.getType() == type)
next = i;
}
}
public boolean hasNext()
{
align();
return next != null;
}
public T next()
{
if (!hasNext())
throw new NoSuchElementException();
T t = next;
next = null;
return t;
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
public static Iterator<PDLItem> flatten(final PDLBlock items)
{
return new Iterator<PDLItem>()
{
List<Iterator<PDLItem>> list;
Iterator<PDLItem> iter = items.iterator();
public boolean hasNext()
{
return iter.hasNext() || (list != null && !list.isEmpty());
}
public PDLItem next()
{
if (!hasNext())
throw new NoSuchElementException();
PDLItem item;
if (!iter.hasNext())
{
iter = list.remove(0);
}
item = iter.next();
switch (item.getType())
{
// no children
case MessageId:
case Constant:
case ImplicitVariable:
case Label:
case Variable:
case VariableList:
case PacketRef:
case PacketRefList:
case Fail:
break;
// children but not a sequence
case Choice:
case SwitchStatement:
break;
// have children
case Block:
case Conditional:
case Optional:
{
PDLBlock block = (PDLBlock) item;
if (block.getItemCount()>0)
{
if (list == null)
list = new ArrayList<Iterator<PDLItem>>();
Iterator<PDLItem> iter = block.iterator();
list.add(iter);
}
break;
}
// error: item is undefined
default:
PDLUtils.unknownItemTypeError(item.getType());
break;
}
return item;
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
public static void unknownItemTypeError(PDLItem item)
{
throw new InternalError("unknown item type: "+item.getType()+"; item: "+item);
}
public static void unknownItemTypeError(PDLItemType type)
{
throw new InternalError("unknown item type: "+type);
}
}