/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2004 Intel Corporation
*
* 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.
*
* @version $Id$
*/
package com.intel.bluetooth;
import java.io.OutputStream;
import java.io.IOException;
import java.util.Enumeration;
import javax.bluetooth.DataElement;
import javax.bluetooth.UUID;
class SDPOutputStream extends OutputStream {
OutputStream dst;
public SDPOutputStream(OutputStream out) {
this.dst = out;
}
public void write(int oneByte) throws IOException {
this.dst.write(oneByte);
}
private void writeLong(long l, int size) throws IOException {
for (int i = 0; i < size; i++) {
write((int) (l >> (size - 1 << 3)));
l <<= 8;
}
}
private void writeBytes(byte[] b) throws IOException {
for (int i = 0; i < b.length; i++) {
write(b[i]);
}
}
static int getLength(DataElement d) {
switch (d.getDataType()) {
case DataElement.NULL:
return 1;
case DataElement.BOOL:
case DataElement.U_INT_1:
case DataElement.INT_1:
return 2;
case DataElement.U_INT_2:
case DataElement.INT_2:
return 3;
case DataElement.U_INT_4:
case DataElement.INT_4:
return 5;
case DataElement.U_INT_8:
case DataElement.INT_8:
return 9;
case DataElement.U_INT_16:
case DataElement.INT_16:
return 17;
case DataElement.UUID:
long uuid = Utils.UUIDTo32Bit((UUID) d.getValue());
if (uuid == -1) {
return 1 + 16;
} else if (uuid <= 0xFFFF) {
return 1 + 2;
} else {
return 1 + 4;
}
case DataElement.STRING: {
byte[] b;
if (BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_SDP_STRING_ENCODING_ASCII, false)) {
b = Utils.getASCIIBytes((String) d.getValue());
} else {
b = Utils.getUTF8Bytes((String) d.getValue());
}
if (b.length < 0x100) {
return b.length + 2;
} else if (b.length < 0x10000) {
return b.length + 3;
} else {
return b.length + 5;
}
}
case DataElement.URL: {
byte[] b = Utils.getASCIIBytes((String) d.getValue());
if (b.length < 0x100) {
return b.length + 2;
} else if (b.length < 0x10000) {
return b.length + 3;
} else {
return b.length + 5;
}
}
case DataElement.DATSEQ:
case DataElement.DATALT: {
int result = 1;
for (Enumeration e = (Enumeration) d.getValue(); e.hasMoreElements();) {
result += getLength((DataElement) e.nextElement());
}
if (result < 0xff) {
result += 1;
} else if (result < 0xFFFF) {
result += 2;
} else {
result += 4;
}
return result;
}
default:
throw new IllegalArgumentException();
}
}
void writeElement(DataElement d) throws IOException {
switch (d.getDataType()) {
case DataElement.NULL:
write(0 | 0);
break;
case DataElement.U_INT_1:
write(8 | 0);
writeLong(d.getLong(), 1);
break;
case DataElement.U_INT_2:
write(8 | 1);
writeLong(d.getLong(), 2);
break;
case DataElement.U_INT_4:
write(8 | 2);
writeLong(d.getLong(), 4);
break;
case DataElement.U_INT_8:
write(8 | 3);
writeBytes((byte[]) d.getValue());
break;
case DataElement.U_INT_16:
write(8 | 4);
writeBytes((byte[]) d.getValue());
break;
case DataElement.INT_1:
write(16 | 0);
writeLong(d.getLong(), 1);
break;
case DataElement.INT_2:
write(16 | 1);
writeLong(d.getLong(), 2);
break;
case DataElement.INT_4:
write(16 | 2);
writeLong(d.getLong(), 4);
break;
case DataElement.INT_8:
write(16 | 3);
writeLong(d.getLong(), 8);
break;
case DataElement.INT_16:
write(16 | 4);
writeBytes((byte[]) d.getValue());
break;
case DataElement.UUID:
long uuid = Utils.UUIDTo32Bit((UUID) d.getValue());
if (uuid == -1) {
write(24 | 4);
writeBytes(Utils.UUIDToByteArray((UUID) d.getValue()));
} else if (uuid <= 0xFFFF) {
write(24 | 1);
writeLong(uuid, 2);
} else {
write(24 | 2);
writeLong(uuid, 4);
}
break;
case DataElement.STRING: {
byte[] b;
if (BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_SDP_STRING_ENCODING_ASCII, false)) {
b = Utils.getASCIIBytes((String) d.getValue());
} else {
b = Utils.getUTF8Bytes((String) d.getValue());
}
if (b.length < 0x100) {
write(32 | 5);
writeLong(b.length, 1);
} else if (b.length < 0x10000) {
write(32 | 6);
writeLong(b.length, 2);
} else {
write(32 | 7);
writeLong(b.length, 4);
}
writeBytes(b);
break;
}
case DataElement.BOOL:
write(40 | 0);
writeLong(d.getBoolean() ? 1 : 0, 1);
break;
case DataElement.DATSEQ: {
int sizeDescriptor;
int len = getLength(d);
int lenSize;
if (len < (0xff + 2)) {
sizeDescriptor = 5;
lenSize = 1;
} else if (len < (0xFFFF + 3)) {
sizeDescriptor = 6;
lenSize = 2;
} else {
sizeDescriptor = 7;
lenSize = 4;
}
len -= (1 + lenSize);
write(48 | sizeDescriptor);
writeLong(len, lenSize);
for (Enumeration e = (Enumeration) d.getValue(); e.hasMoreElements();) {
writeElement((DataElement) e.nextElement());
}
break;
}
case DataElement.DATALT: {
int sizeDescriptor;
int len = getLength(d) - 5;
int lenSize;
if (len < 0xff) {
sizeDescriptor = 5;
lenSize = 1;
} else if (len < 0xFFFF) {
sizeDescriptor = 6;
lenSize = 2;
} else {
sizeDescriptor = 7;
lenSize = 4;
}
write(56 | sizeDescriptor);
writeLong(len, lenSize);
for (Enumeration e = (Enumeration) d.getValue(); e.hasMoreElements();) {
writeElement((DataElement) e.nextElement());
}
break;
}
case DataElement.URL: {
byte[] b = Utils.getASCIIBytes((String) d.getValue());
if (b.length < 0x100) {
write(64 | 5);
writeLong(b.length, 1);
} else if (b.length < 0x10000) {
write(64 | 6);
writeLong(b.length, 2);
} else {
write(64 | 7);
writeLong(b.length, 4);
}
writeBytes(b);
break;
}
default:
throw new IOException();
}
}
}