📄 sdprecord.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
// SdpRecord.cpp : Implementation of CSdpRecord
#include "stdafx.h"
#include "BthAPI.h"
#include "sdplib.h"
#include "SdpNodeList.h"
#include "SdpRecord.h"
#include "util.h"
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
#include <mlang.h>
#include <assert.h>
struct MIBEnumToCharset {
USHORT mibeNum;
WCHAR* pszCharset;
};
//
// MIBE numbers came from iana website
// (http://www.isi.edu/in-notes/iana/assignments/character-sets)
//
// matching string names were manually matched from the iana site in the table
// in nt\shell\ext\mlan\mimedb.cpp
//
const MIBEnumToCharset g_MibeMapping[] = {
{3, L"us-ascii"}, // ascii
{4, L"iso-8859-1"}, // latin
{5, L"iso-8859-2"}, // latin2
{6, L"iso-8859-3"}, // latin3
{7, L"iso-8859-4"}, // latin4
{8, L"iso-8859-5"}, // latin cyrillic
{9, L"iso-8859-6"}, // arabic
{10, L"iso-8859-7"}, // latin greek
{11, L"iso-8859-8"}, // latin hebrew
{12, L"iso-8859-9"}, // latin5
{17, L"ms_Kanji"}, // kanji / japanese
{18, L"euc-jp"},
{19, L"Extended_UNIX_Code_Packed_Format_for_Japanese"},
{25, L"NS_4551-1"}, // danish, norwegian
{36, L"iso-ir-149"}, // korean
{37, L"iso-2022-kr" }, // korean
{38, L"euc-kr" }, // korean
{39, L"iso-2022-jp" }, // japanese
{40, L"iso-2022-jp" }, // L"iso-2022-jp-2" really, but no match in IMultiLanguage
{45, L"csISOLatinGreek" },
{57, L"GB_2312-80"},
{85, L"ISO_8859-8-I"},
{103, L"unicode-1-1-utf-7"},
{106, L"utf-8"},
{109, L"iso-8859-13"},
{111, L"iso-8859-15"},
{1010, L"csUnicode11"},
{1012, L"utf-7"},
{1013, L"UTF-16BE"},
{1014, L"UTF-16LE"},
{1015, L"utf-16"},
{2009, L"ibm850"},
{2010, L"ibm852"},
{2011, L"IBM437"},
{2024, L"csWindows31J"},
{2025, L"GB2312"}, // PRC mixed set
{2026, L"Big5"}, // Chinese for taiwan mb set
{2027, L"macintosh"},
{2028, L"ebcdic-cp-us"},
{2047, L"ibm857"},
{2049, L"ibm861"},
{2054, L"ibm869"},
{2084, L"koi8-r"},
{2085, L"hz-gb-2312"},
{2086, L"ibm866"},
{2087, L"ibm775"},
{2088, L"koi8-u"},
{2250, L"windows-1250"},
{2251, L"windows-1251"},
{2252, L"windows-1252"},
{2253, L"windows-1253"},
{2253, L"windows-1253"},
{2254, L"windows-1254"},
{2255, L"windows-1255"},
{2256, L"windows-1256"},
{2257, L"windows-1257"},
{2258, L"windows-1258"},
{2259, L"TIS-620"},
};
const ULONG g_MibeMappingCount = sizeof(g_MibeMapping) / sizeof(g_MibeMapping[0]);
#endif // UNDER_CE
#define LOCK_LIST() ListLock l(&listLock)
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
WCHAR* FindCharset(USHORT mibeNum)
{
ULONG iStart = 0, iEnd = g_MibeMappingCount-1, iMiddle;
//
// Binary search through the array (sorted by mibeNum)
//
while (iStart <= iEnd) {
iMiddle = (iStart + iEnd) / 2;
if (mibeNum == g_MibeMapping[iMiddle].mibeNum) {
return g_MibeMapping[iMiddle].pszCharset;
}
else if (mibeNum > g_MibeMapping[iMiddle].mibeNum) {
iStart = iMiddle + 1;
}
else {
iEnd = iMiddle - 1;
}
}
return NULL;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// CSdpRecord
void CSdpRecord::Init(void)
{
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
m_pUnkMarshaler = NULL;
#endif
locked = 0;
InitializeCriticalSection(&listLock);
}
CSdpRecord::~CSdpRecord()
{
DeleteCriticalSection(&listLock);
DestroyRecord();
}
void CSdpRecord::LockRecord(UCHAR lock)
{
LOCK_LIST();
if (lock) {
locked++;
}
else {
lock--;
}
nodeList.Lock(lock);
}
void CSdpRecord::DestroyRecord(void)
{
nodeList.Destroy();
}
STDMETHODIMP CSdpRecord::CreateFromStream(UCHAR *pStream, ULONG size)
{
NTSTATUS status;
if (pStream == NULL) {
return E_POINTER;
}
//
// validate the format of the stream
//
status = SdpIsStreamRecord(pStream, size);
if (!NT_SUCCESS(status)) {
return E_INVALIDARG;
}
//
// make sure that each attribute is of the correct format
//
USHORT attribId = 0xFFFF;
status = SdpVerifyServiceRecord(pStream, size, 0, &attribId);
if (!NT_SUCCESS(status)) {
return E_INVALIDARG;
}
UCHAR type, sizeIndex;
SdpRetrieveHeader(pStream, type, sizeIndex);
pStream++;
ULONG elementSize, storageSize;
SdpRetrieveVariableSize(pStream, sizeIndex, &elementSize, &storageSize);
LOCK_LIST();
if (locked) {
return E_ACCESSDENIED;
}
HRESULT err;
if (elementSize > 0) {
DestroyRecord();
err = nodeList.CreateFromStream(pStream + storageSize, elementSize);
if (!SUCCEEDED(err)) {
DestroyRecord();
}
}
else {
err = S_OK;
}
return err;
}
STDMETHODIMP CSdpRecord::WriteToStream(
UCHAR **ppStream,
ULONG *pStreamSize,
ULONG preSize,
ULONG postSize
)
{
if (ppStream == NULL || pStreamSize == NULL) {
return E_POINTER;
}
HRESULT err = S_OK;
LockRecord(TRUE);
ULONG streamSize, size;
streamSize = nodeList.GetStreamSize();
size = streamSize + GetContainerHeaderSize(streamSize);
PUCHAR stream = (PUCHAR) CoTaskMemAlloc(size + preSize + postSize);
if (stream) {
*ppStream = stream;
*pStreamSize = size;
ZeroMemory(*ppStream, size + preSize + postSize);
stream = WriteVariableSizeToStream(SDP_TYPE_SEQUENCE, streamSize, stream + preSize);
nodeList.WriteStream(stream);
}
LockRecord(FALSE);
return err;
}
STDMETHODIMP CSdpRecord::SetAttribute(USHORT attribute, NodeData *pData)
{
PSDP_NODE pNode = NULL;
//
// pData == NULL signifies removal
//
if (pData != NULL) {
HRESULT err = CreateSdpNodeFromNodeData(pData, &pNode);
if (!SUCCEEDED(err)) {
return err;
}
#if 0
//
// Check its format. For universal attributes, we know the format of the
// attribute, so convert this node to a stream and see if it is the correct
// one
//
// Only check if we know the format
//
if (attribute <= 0x200) {
PSDP_NODE pTree;
PUCHAR stream;
ULONG size;
NTSTATUS status;
pTree = SdpCreateNodeTree();
if (pTree == NULL) {
SdpFreeOrphanedNode(pNode);
return E_OUTOFMEMORY;
}
status = SdpAppendNodeToContainerNode(pTree, pNode);
if (!NT_SUCCESS(status)) {
SdpFreeOrphanedNode(pNode);
SdpFreeTree(pTree);
return MapNtStatusToHresult(status);
}
status = SdpStreamFromTree(pTree, &stream, &size);
if (!NT_SUCCESS(status)) {
//
// no need to free the orphan b/c it is now a part of the tree
//
SdpFreeTree(pTree);
return MapNtStatusToHresult(status);
}
//
// verify the attribute value
//
status = SdpVerifyServiceRecord(stream,
size,
VERIFY_STREAM_IS_ATTRIBUTE_VALUE,
&attribute);
SdpFreePool(stream);
stream = NULL;
if (!NT_SUCCESS(status)) {
SdpFreeTree(pTree);
return MapNtStatusToHresult(status);
}
//
// Get the node out of the linked list so we can insert it into the
// nodeList
//
PLIST_ENTRY entry = Sdp_RemoveHeadList(&pTree->hdr.Link);
pNode = CONTAINING_RECORD(entry, SDP_NODE, hdr.Link);
Sdp_InitializeListHead(&pNode->hdr.Link);
//
// don't need the tree root anymore
//
SdpFreeTree(pTree);
}
#endif // 0
}
LOCK_LIST();
if (locked) {
return E_ACCESSDENIED;
}
// NTSTATUS status = SdpAddAttributeToTree((PSDP_NODE) &nodeList, attribute, pNode);
NTSTATUS status = SdpAddAttributeToNodeHeader(&nodeList, attribute, pNode);
if (!NT_SUCCESS(status)) {
return MapNtStatusToHresult(status);
}
//
// successful remove, maintain the node count (id and value are now gone)
//
if (pNode == NULL) {
nodeList.nodeCount -= 2;
}
return S_OK;
}
STDMETHODIMP CSdpRecord::SetAttributeFromStream(USHORT attribute, UCHAR *pStream, ULONG size)
{
PSDP_NODE pNode = NULL;
if (!NT_SUCCESS(ValidateStream(pStream, size, NULL, NULL, NULL))) {
return E_INVALIDARG;
}
if (!NT_SUCCESS(SdpVerifyServiceRecord(pStream,
size,
VERIFY_STREAM_IS_ATTRIBUTE_VALUE,
&attribute))) {
return E_INVALIDARG;
}
LOCK_LIST();
if (locked) {
return E_ACCESSDENIED;
}
//
// if pStream or size are 0, then the caller wants to remove the attribute
//
if (pStream != NULL && size != 0) {
SdpNodeList tmpList;
HRESULT err;
err = tmpList.CreateFromStream(pStream, size);
if (!SUCCEEDED(err)) {
return err;
}
//
// Attribute values can be just one element, whether it be a uint or a
// container
//
if (tmpList.nodeCount != 1) {
return E_INVALIDARG;
}
PLIST_ENTRY entry = Sdp_RemoveHeadList(&tmpList.Link);
pNode = CONTAINING_RECORD(entry, SDP_NODE, hdr.Link);
Sdp_InitializeListHead(&pNode->hdr.Link);
}
// NTSTATUS status = SdpAddAttributeToTree((PSDP_NODE) &nodeList, attribute, pNode);
NTSTATUS status = SdpAddAttributeToNodeHeader(&nodeList, attribute, pNode);
if (!NT_SUCCESS(status)) {
SdpFreeOrphanedNode(pNode);
return MapNtStatusToHresult(status);
}
//
// successful remove, maintain the node count (id and value are now gone)
//
if (pNode == NULL) {
nodeList.nodeCount -= 2;
}
return S_OK;
}
PSDP_NODE CSdpRecord::GetAttributeValueNode(USHORT attribute)
{
PLIST_ENTRY current = nodeList.Link.Flink;
while (1) {
PSDP_NODE pId, pValue;
pId = CONTAINING_RECORD(current, SDP_NODE, hdr.Link);
current = current->Flink;
pValue = CONTAINING_RECORD(current, SDP_NODE, hdr.Link);
if (pId->u.uint16 == attribute) {
return pValue;
}
current = current->Flink;
if (current == &nodeList.Link) {
//
// end of the list, no match
//
return NULL;
}
}
}
STDMETHODIMP CSdpRecord::GetAttribute(USHORT attribute, NodeData *pData)
{
if (pData == NULL) {
return E_POINTER;
}
LOCK_LIST();
if (nodeList.nodeCount < 2) {
return E_FAIL;
}
PSDP_NODE pNode = GetAttributeValueNode(attribute);
if (pNode) {
CreateNodeDataFromSdpNode(pNode, pData);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -