/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2000-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine 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. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.io.device.bluetooth; import totalcross.io.ByteArrayStream; import totalcross.io.DataStream; import totalcross.io.IOException; import totalcross.sys.CharacterConverter; import totalcross.sys.Convert; import totalcross.sys.UTF8CharacterConverter; /** * Parses service record info. * * @since TotalCross 1.27 */ class SDPInputStream extends DataStream { final private static UTF8CharacterConverter converterUTF8 = new UTF8CharacterConverter(); final private static CharacterConverter converterASCII = new CharacterConverter(); public SDPInputStream(byte[] input) { super(new ByteArrayStream(input), true); } private byte[] readBytes(int size) throws IOException { byte[] buffer = new byte[size]; readBytes(buffer); return buffer; } public DataElement readElement() throws IOException { int header = readByte(); int type = header >> 3 & 0x1f; int sizeDescriptor = header & 0x07; switch (type) { case 0: // NULL return new DataElement(DataElement.NULL); case 1: // U_INT switch (sizeDescriptor) { case 0: return new DataElement(DataElement.U_INT_1, readUnsignedByte()); case 1: return new DataElement(DataElement.U_INT_2, readUnsignedShort()); case 2: return new DataElement(DataElement.U_INT_4, readUnsignedInt()); case 3: return new DataElement(DataElement.U_INT_8, readBytes(8)); case 4: return new DataElement(DataElement.U_INT_16, readBytes(16)); default: throw new IOException(); } case 2: // INT switch (sizeDescriptor) { case 0: return new DataElement(DataElement.INT_1, readByte()); case 1: return new DataElement(DataElement.INT_2, readShort()); case 2: return new DataElement(DataElement.INT_4, readInt()); case 3: return new DataElement(DataElement.INT_8, readLong()); case 4: return new DataElement(DataElement.INT_16, readBytes(16)); default: throw new IOException(); } case 3: // UUID { UUID uuid = null; switch (sizeDescriptor) { case 1: uuid = new UUID(readUnsignedShort()); break; case 2: uuid = new UUID(readUnsignedInt()); break; case 4: uuid = new UUID(Convert.bytesToHexString(readBytes(16)), false); break; default: throw new IOException(); } return new DataElement(DataElement.UUID, uuid); } case 4: // STRING { int length = -1; switch (sizeDescriptor) { case 5: length = readUnsignedByte(); break; case 6: length = readUnsignedShort(); break; case 7: length = readInt(); break; default: throw new IOException(); } byte[] bytes = readBytes(length); return new DataElement(DataElement.STRING, new String(converterUTF8.bytes2chars(bytes, 0, bytes.length))); } case 5: // BOOL return new DataElement(readBoolean()); case 6: // DATSEQ { long length; switch (sizeDescriptor) { case 5: length = readUnsignedByte(); break; case 6: length = readUnsignedShort(); break; case 7: length = readUnsignedInt(); break; default: throw new IOException(); } DataElement element = new DataElement(DataElement.DATSEQ); ByteArrayStream inputStream = (ByteArrayStream) super.stream; int started = inputStream.getPos(); for (long end = started + length; inputStream.getPos() < end;) element.addElement(readElement()); if ((started + length) != inputStream.getPos()) throw new IOException("DATSEQ size corruption " + (started + length - inputStream.getPos())); return element; } case 7: // DATALT { long length; switch (sizeDescriptor) { case 5: length = readUnsignedByte(); break; case 6: length = readUnsignedShort(); break; case 7: length = readUnsignedInt(); break; default: throw new IOException(); } DataElement element = new DataElement(DataElement.DATALT); ByteArrayStream inputStream = (ByteArrayStream) super.stream; int started = inputStream.getPos(); for (long end = started + length; inputStream.getPos() < end;) element.addElement(readElement()); if ((started + length) != inputStream.getPos()) throw new IOException("DATALT size corruption " + (started + length - inputStream.getPos())); return element; } case 8: // URL { int length; switch (sizeDescriptor) { case 5: length = readUnsignedByte(); break; case 6: length = readUnsignedShort(); break; case 7: length = readInt(); break; default: throw new IOException(); } byte[] bytes = readBytes(length); return new DataElement(DataElement.URL, new String(converterASCII.bytes2chars(bytes, 0, bytes.length))); } default: throw new IOException("Unknown type " + type); } } }