//-------- private static void DumpAdditionalProtocolDescriptorLists(TextWriter writer, int depth, ServiceElement element) { Debug.Assert(element.ElementType == ElementType.ElementSequence); // // Is a list of PDLs foreach (ServiceElement curList in element.GetValueAsElementList()) { DumpProtocolDescriptorList(writer, depth + 1, curList); }//foreach }
private static void DumpProtocolDescriptorListList(TextWriter writer, int depth, ServiceElement element) { // The list. Debug.Assert(element.ElementType == ElementType.ElementSequence); WritePrefix(writer, depth); writer.Write("( "); bool firstLayer = true; foreach (ServiceElement layer in element.GetValueAsElementList()) { ServiceElement[] items = layer.GetValueAsElementArray(); int used = 0; Debug.Assert(items[used].ElementTypeDescriptor == ElementTypeDescriptor.Uuid); Guid protoGuid = items[used].GetValueAsUuid(); string protoStr; HackProtocolId proto = GuidToHackProtocolId(protoGuid, out protoStr); // used++; writer.Write("{0}( {1}", (firstLayer ? string.Empty : ", "), protoStr); if (proto == HackProtocolId.L2Cap) { if (used < items.Length) { Debug.Assert(items[used].ElementType == ElementType.UInt16); var u16 = (ushort)items[used].Value; HackProtocolServiceMultiplexer psm = unchecked ((HackProtocolServiceMultiplexer)u16); used++; writer.Write(", PSM={0}", Enum_ToStringNameOrHex(psm)); } } else if (proto == HackProtocolId.Rfcomm) { if (used < items.Length) { Debug.Assert(items[used].ElementType == ElementType.UInt8); byte channelNumber = (byte)items[used].Value; used++; writer.Write(", ChannelNumber={0}", channelNumber); } } // Others include BNEP for instance, which isn't defined in the base SDP spec. if (used < items.Length) { writer.Write(", ..."); } writer.Write(" )"); firstLayer = false; }//foreach layer writer.WriteLine(" )"); }
private static void DumpProtocolDescriptorList(TextWriter writer, int depth, ServiceElement element) { Debug.Assert(element.ElementType == ElementType.ElementAlternative || element.ElementType == ElementType.ElementSequence); // // If passes a list of alternatives, each a protocol descriptor list, // then call ourselves on each list. if (element.ElementType == ElementType.ElementAlternative) { foreach (ServiceElement curStack in element.GetValueAsElementList()) { DumpProtocolDescriptorListList(writer, depth + 1, curStack); }//foreach return; } //else DumpProtocolDescriptorListList(writer, depth, element); }
private static void DumpRawElement(TextWriter writer, int depth, ServiceElement elem) { WritePrefix(writer, depth); if (elem.ElementType == ElementType.ElementSequence || elem.ElementType == ElementType.ElementAlternative) { writer.WriteLine("{0}", elem.ElementType); foreach (ServiceElement element in elem.GetValueAsElementList()) { DumpRawElement(writer, depth + 1, element); } } else if (elem.ElementType == ElementType.Nil) { writer.WriteLine("Nil:"); } else if (elem.ElementType == ElementType.TextString || elem.ElementType == ElementType.Boolean || elem.ElementType == ElementType.Url) { // Non-numeric types writer.WriteLine("{0}: {1}", elem.ElementType, elem.Value); } else if (elem.ElementType == ElementType.Uuid128) { writer.WriteLine("{0}: {1}", elem.ElementType, elem.Value); } else if (elem.ElementType == ElementType.UInt128 || elem.ElementType == ElementType.Int128) { string valueText = BitConverter.ToString((byte[])elem.Value); writer.WriteLine("{0}: {1}", elem.ElementType, valueText); } else { writer.WriteLine("{0}: 0x{1:X}", elem.ElementType, elem.Value); //{catch(?FOrmatExptn){ // writer.WriteLine("{0}: 0x{1}", elem.Type, elem.Value); //} } }
// TODO GetRfcommChannelElement(ServiceAttribute attr) Could be public -> Tests! internal static ServiceElement GetChannelElement(ServiceAttribute attr, BluetoothProtocolDescriptorType proto, out bool?isSimpleRfcomm) { if (proto != BluetoothProtocolDescriptorType.L2Cap && proto != BluetoothProtocolDescriptorType.Rfcomm) { throw new ArgumentException("Can only fetch RFCOMM or L2CAP element."); } // isSimpleRfcomm = true; Debug.Assert(attr != null, "attr != null"); ServiceElement e0 = attr.Value; if (e0.ElementType == ElementType.ElementAlternative) { Trace.WriteLine("Don't support ElementAlternative ProtocolDescriptorList values."); goto NotFound; } else if (e0.ElementType != ElementType.ElementSequence) { Trace.WriteLine("Bad ProtocolDescriptorList base element."); goto NotFound; } IList <ServiceElement> protoStack = e0.GetValueAsElementList(); IEnumerator <ServiceElement> etor = protoStack.GetEnumerator(); ServiceElement layer; IList <ServiceElement> layerContent; ServiceElement channelElement; // -- L2CAP Layer -- if (!etor.MoveNext()) { Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "Protocol stack truncated before {0}.", "L2CAP")); goto NotFound; } layer = etor.Current; //cast here are for non-Generic version. layerContent = layer.GetValueAsElementList(); if (layerContent[0].GetValueAsUuid() != BluetoothProtocol.L2CapProtocol) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "Bad protocol stack, layer {0} is not {1}.", 1, "L2CAP")); goto NotFound; } bool hasPsmEtc = layerContent.Count != 1; // Cast for FX1.1 object isSimpleRfcomm = (bool)isSimpleRfcomm && !hasPsmEtc; if (proto == BluetoothProtocolDescriptorType.L2Cap) { if (layerContent.Count < 2) { Trace.WriteLine("L2CAP PSM element was requested but the L2CAP layer in this case hasn't a second element."); goto NotFound; } channelElement = (ServiceElement)layerContent[1]; goto Success; } // // -- RFCOMM Layer -- if (!etor.MoveNext()) { Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "Protocol stack truncated before {0}.", "RFCOMM")); goto NotFound; } layer = etor.Current; layerContent = layer.GetValueAsElementList(); if (layerContent[0].GetValueAsUuid() != BluetoothProtocol.RFCommProtocol) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "Bad protocol stack, layer {0} is not {1}.", 2, "RFCOMM")); goto NotFound; } // if (layerContent.Count < 2) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "Bad protocol stack, layer {0} hasn't a second element.", 2)); goto NotFound; } channelElement = (ServiceElement)layerContent[1]; if (channelElement.ElementType != ElementType.UInt8) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "Bad protocol stack, layer {0} is not UInt8.", 2)); goto NotFound; } // Success // // -- Any remaining layer(s) -- bool extraLayers = etor.MoveNext(); isSimpleRfcomm = (bool)isSimpleRfcomm && !extraLayers; Success: // return(channelElement); NotFound: isSimpleRfcomm = null; return(null); }
private static XElement GetAttributeValue(ServiceElement value) { // There isn't much formal documentation on the BlueZ SDP XML format. // The actual serialization is implemented in the convert_raw_data_to_xml // function at https://github.com/bluez/bluez/blob/9be85f867856195e16c9b94b605f65f6389eda33/src/sdp-xml.c#L637 switch (value.ElementType) { case ElementType.Nil: return(new XElement("nil")); case ElementType.Boolean: var boolean = new XElement("boolean"); boolean.SetAttributeValue("value", (bool)value.Value ? "true" : "false"); return(boolean); case ElementType.UInt8: var uint8 = new XElement("uint8"); uint8.SetAttributeValue("value", $"0x{value.Value:x2}"); return(uint8); case ElementType.UInt16: var uint16 = new XElement("uint16"); uint16.SetAttributeValue("value", $"0x{value.Value:x4}"); return(uint16); case ElementType.UInt32: var uint32 = new XElement("uint32"); uint32.SetAttributeValue("value", $"0x{value.Value:x8}"); return(uint32); case ElementType.UInt64: var uint64 = new XElement("uint64"); uint64.SetAttributeValue("value", $"0x{value.Value:x16}"); return(uint64); case ElementType.Int8: var int8 = new XElement("int8"); int8.SetAttributeValue("value", $"{value.Value:d}"); return(int8); case ElementType.Int16: var int16 = new XElement("int16"); int16.SetAttributeValue("value", $"{value.Value:d}"); return(int16); case ElementType.Int32: var int32 = new XElement("int32"); int32.SetAttributeValue("value", $"{value.Value:d}"); return(int32); case ElementType.Int64: var int64 = new XElement("int64"); int64.SetAttributeValue("value", $"{value.Value:d}"); return(int64); case ElementType.Uuid16: var uuid16 = new XElement("uuid"); uuid16.SetAttributeValue("value", $"0x{value.Value:x4}"); return(uuid16); case ElementType.Uuid32: var uuid32 = new XElement("uuid"); uuid32.SetAttributeValue("value", $"0x{value.Value:x8}"); return(uuid32); case ElementType.Uuid128: var uuid128 = new XElement("uuid"); uuid128.SetAttributeValue("value", $"0x{value.Value:D}"); return(uuid128); case ElementType.TextString: var textString = new XElement("text"); if (value.Value is byte[]) { textString.SetAttributeValue("encoding", "hex"); textString.SetAttributeValue("value", GetHexString((byte[])value.Value)); } else { textString.SetAttributeValue("value", (string)value.Value); } return(textString); case ElementType.Url: var url = new XElement("url"); url.SetAttributeValue("value", value.Value); return(url); case ElementType.ElementSequence: var sequence = new XElement("sequence"); foreach (var child in value.GetValueAsElementList()) { sequence.Add(GetAttributeValue(child)); } return(sequence); case ElementType.ElementAlternative: var alternate = new XElement("alternate"); foreach (var child in value.GetValueAsElementList()) { alternate.Add(GetAttributeValue(child)); } return(alternate); default: throw new ArgumentOutOfRangeException(nameof(value)); } }
/// <summary> /// Create the element in the buffer starting at offset, and return its totalLength. /// </summary> /// <param name="element">The element to create. /// </param> /// <param name="buf">The byte array to write the encoded element to. /// </param> /// <param name="offset">The place to start writing in <paramref name="buf"/>. /// </param> /// /// <returns>The total length of the encoded element written to the buffer /// </returns> protected virtual int CreateElement(ServiceElement element, byte[] buf, int offset) { int totalLength; // if (element.ElementTypeDescriptor == ElementTypeDescriptor.ElementSequence || element.ElementTypeDescriptor == ElementTypeDescriptor.ElementAlternative) { HeaderWriteState headerState; int curLen; curLen = MakeVariableLengthHeader(buf, offset, element.ElementTypeDescriptor, out headerState); offset += curLen; foreach (ServiceElement childElement in element.GetValueAsElementList()) { curLen = CreateElement(childElement, buf, offset); offset += curLen; }//for CompleteHeaderWrite(headerState, buf, offset, out totalLength); //---------------- } else if (element.ElementTypeDescriptor == ElementTypeDescriptor.UnsignedInteger || element.ElementTypeDescriptor == ElementTypeDescriptor.TwosComplementInteger) { switch (element.ElementType) { case ElementType.UInt8: WriteByte(element, (Byte)element.Value, buf, ref offset, out totalLength); break; case ElementType.Int8: WriteSByte(element, (SByte)element.Value, buf, ref offset, out totalLength); break; case ElementType.UInt16: WriteUInt16(element, (UInt16)element.Value, buf, ref offset, out totalLength); break; case ElementType.Int16: WriteInt16(element, (Int16)element.Value, buf, ref offset, out totalLength); break; case ElementType.UInt32: WriteUInt32(element, (UInt32)element.Value, buf, ref offset, out totalLength); break; case ElementType.Int32: WriteInt32(element, (Int32)element.Value, buf, ref offset, out totalLength); break; case ElementType.UInt64: WriteUInt64(element, (UInt64)element.Value, buf, ref offset, out totalLength); break; case ElementType.Int64: WriteInt64(element, (Int64)element.Value, buf, ref offset, out totalLength); break; default: System.Diagnostics.Debug.Fail(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Unexpected integral type '{0}'.", element.ElementType)); totalLength = 0; break; }//switch //---------------- } else if (element.ElementTypeDescriptor == ElementTypeDescriptor.Uuid) { if (element.ElementType == ElementType.Uuid16) { WriteUInt16(element, (UInt16)element.Value, buf, ref offset, out totalLength); } else if (element.ElementType == ElementType.Uuid32) { WriteUInt32(element, (UInt32)element.Value, buf, ref offset, out totalLength); } else { //TODO If the 'Guid' holds a 'Bluetooth-based' UUID, then should we write the short form? byte[] bytes; System.Diagnostics.Debug.Assert(element.ElementType == ElementType.Uuid128); Guid hostGuid = (Guid)element.Value; Guid netGuid = BluetoothAddress.HostToNetworkOrder(hostGuid); bytes = netGuid.ToByteArray(); WriteFixedLength(element, bytes, buf, ref offset, out totalLength); } //---------------- } else if (element.ElementTypeDescriptor == ElementTypeDescriptor.Url) { Uri uri = element.GetValueAsUri(); String uriString = uri.ToString(); byte[] valueBytes = System.Text.Encoding.ASCII.GetBytes(uriString); WriteVariableLength(element, valueBytes, buf, ref offset, out totalLength); //---------------- } else if (element.ElementTypeDescriptor == ElementTypeDescriptor.TextString) { byte[] valueBytes; String valueString = element.Value as String; if (valueString != null) { valueBytes = System.Text.Encoding.UTF8.GetBytes(valueString); } else { System.Diagnostics.Debug.Assert(element.Value is byte[]); valueBytes = (byte[])element.Value; } WriteVariableLength(element, valueBytes, buf, ref offset, out totalLength); //---------------- } else if (element.ElementTypeDescriptor == ElementTypeDescriptor.Nil) { WriteFixedLength(element, new byte[0], buf, ref offset, out totalLength); //---------------- } else if (element.ElementTypeDescriptor == ElementTypeDescriptor.Boolean) { bool value = (bool)element.Value; byte[] valueBytes = new byte[1]; valueBytes[0] = value ? (byte)1 : (byte)0; WriteFixedLength(element, valueBytes, buf, ref offset, out totalLength); //---------------- } else { totalLength = 0; } // if (totalLength == 0) { throw new NotSupportedException(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Creation of element type '{0}' not implemented.", element.ElementType)); } return(totalLength); }
private static void DumpElement(TextWriter writer, int depth, ServiceElement elem) { WritePrefix(writer, depth); if (elem.ElementType == ElementType.ElementSequence || elem.ElementType == ElementType.ElementAlternative) { writer.WriteLine("{0}", elem.ElementType); foreach (ServiceElement element in elem.GetValueAsElementList()) { DumpElement(writer, depth + 1, element); }//for } else if (elem.ElementType == ElementType.Nil) { writer.WriteLine("Nil:"); } else if (elem.ElementType == ElementType.TextString) { DumpString(writer, depth, elem, null); } else if (elem.ElementType == ElementType.Boolean || elem.ElementType == ElementType.Url) { // Non-numeric types writer.WriteLine("{0}: {1}", elem.ElementType, elem.Value); } else { string name = null; string valueText = null; if (elem.ElementTypeDescriptor == ElementTypeDescriptor.Uuid) { if (elem.ElementType == ElementType.Uuid16) { name = BluetoothService.GetName((ushort)elem.Value); } else if (elem.ElementType == ElementType.Uuid32) { name = BluetoothService.GetName((uint)elem.Value); } else { Debug.Assert(elem.ElementType == ElementType.Uuid128); name = BluetoothService.GetName((Guid)elem.Value); valueText = ((Guid)elem.Value).ToString(); } }//if UUID if (valueText == null) { if (elem.ElementTypeDescriptor == ElementTypeDescriptor.Unknown) { valueText = "unknown"; } else if (elem.ElementType == ElementType.UInt128 || elem.ElementType == ElementType.Int128) { valueText = BitConverter.ToString((byte[])elem.Value); } else { valueText = string.Format(System.Globalization.CultureInfo.InvariantCulture, "0x{0:X}", elem.Value); } } if (name == null) { writer.WriteLine("{0}: {1}", elem.ElementType, valueText); } else { writer.WriteLine("{0}: {1} -- {2}", elem.ElementType, valueText, name); } }//else }