1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bluetooth/ObexBase.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,272 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_dom_bluetooth_obexbase_h__ 1.11 +#define mozilla_dom_bluetooth_obexbase_h__ 1.12 + 1.13 +#include "BluetoothCommon.h" 1.14 +#include "nsAutoPtr.h" 1.15 +#include "nsTArray.h" 1.16 + 1.17 +BEGIN_BLUETOOTH_NAMESPACE 1.18 + 1.19 +const char FINAL_BIT = 0x80; 1.20 + 1.21 +/* 1.22 + * Defined in section 2.1 "OBEX Headers", IrOBEX ver 1.2 1.23 + */ 1.24 +enum ObexHeaderId { 1.25 + Count = 0xC0, 1.26 + Name = 0x01, 1.27 + Type = 0x42, 1.28 + Length = 0xC3, 1.29 + TimeISO8601 = 0x44, 1.30 + Time4Byte = 0xC4, 1.31 + Description = 0x05, 1.32 + Target = 0x46, 1.33 + HTTP = 0x47, 1.34 + Body = 0x48, 1.35 + EndOfBody = 0x49, 1.36 + Who = 0x4A, 1.37 + ConnectionId = 0xCB, 1.38 + AppParameters = 0x4C, 1.39 + AuthChallenge = 0x4D, 1.40 + AuthResponse = 0x4E, 1.41 + ObjectClass = 0x4F 1.42 +}; 1.43 + 1.44 +/* 1.45 + * Defined in section 3.3 "OBEX Operations and Opcode definitions", 1.46 + * IrOBEX ver 1.2 1.47 + */ 1.48 +enum ObexRequestCode { 1.49 + Connect = 0x80, 1.50 + Disconnect = 0x81, 1.51 + Put = 0x02, 1.52 + PutFinal = 0x82, 1.53 + Get = 0x03, 1.54 + GetFinal = 0x83, 1.55 + SetPath = 0x85, 1.56 + Abort = 0xFF 1.57 +}; 1.58 + 1.59 +/* 1.60 + * Defined in section 3.2.1 "Response Code values", IrOBEX ver 1.2 1.61 + */ 1.62 +enum ObexResponseCode { 1.63 + Continue = 0x90, 1.64 + 1.65 + Success = 0xA0, 1.66 + Created = 0xA1, 1.67 + Accepted = 0xA2, 1.68 + NonAuthoritativeInfo = 0xA3, 1.69 + NoContent = 0xA4, 1.70 + ResetContent = 0xA5, 1.71 + PartialContent = 0xA6, 1.72 + 1.73 + MultipleChoices = 0xB0, 1.74 + MovedPermanently = 0xB1, 1.75 + MovedTemporarily = 0xB2, 1.76 + SeeOther = 0xB3, 1.77 + NotModified = 0xB4, 1.78 + UseProxy = 0xB5, 1.79 + 1.80 + BadRequest = 0xC0, 1.81 + Unauthorized = 0xC1, 1.82 + PaymentRequired = 0xC2, 1.83 + Forbidden = 0xC3, 1.84 + NotFound = 0xC4, 1.85 + MethodNotAllowed = 0xC5, 1.86 + NotAcceptable = 0xC6, 1.87 + ProxyAuthenticationRequired = 0xC7, 1.88 + RequestTimeOut = 0xC8, 1.89 + Conflict = 0xC9, 1.90 + Gone = 0xCA, 1.91 + LengthRequired = 0xCB, 1.92 + PreconditionFailed = 0xCC, 1.93 + RequestedEntityTooLarge = 0xCD, 1.94 + RequestUrlTooLarge = 0xCE, 1.95 + UnsupprotedMediaType = 0xCF, 1.96 + 1.97 + InternalServerError = 0xD0, 1.98 + NotImplemented = 0xD1, 1.99 + BadGateway = 0xD2, 1.100 + ServiceUnavailable = 0xD3, 1.101 + GatewayTimeout = 0xD4, 1.102 + HttpVersionNotSupported = 0xD5, 1.103 + 1.104 + DatabaseFull = 0xE0, 1.105 + DatabaseLocked = 0xE1, 1.106 +}; 1.107 + 1.108 +class ObexHeader 1.109 +{ 1.110 +public: 1.111 + ObexHeader(ObexHeaderId aId, int aDataLength, const uint8_t* aData) 1.112 + : mId(aId) 1.113 + , mDataLength(aDataLength) 1.114 + , mData(nullptr) 1.115 + { 1.116 + mData = new uint8_t[mDataLength]; 1.117 + memcpy(mData, aData, aDataLength); 1.118 + } 1.119 + 1.120 + ~ObexHeader() 1.121 + { 1.122 + } 1.123 + 1.124 + ObexHeaderId mId; 1.125 + int mDataLength; 1.126 + nsAutoArrayPtr<uint8_t> mData; 1.127 +}; 1.128 + 1.129 +class ObexHeaderSet 1.130 +{ 1.131 +public: 1.132 + ObexHeaderSet(uint8_t aOpcode) : mOpcode(aOpcode) 1.133 + { 1.134 + } 1.135 + 1.136 + ~ObexHeaderSet() 1.137 + { 1.138 + } 1.139 + 1.140 + void AddHeader(ObexHeader* aHeader) 1.141 + { 1.142 + mHeaders.AppendElement(aHeader); 1.143 + } 1.144 + 1.145 + void GetName(nsString& aRetName) const 1.146 + { 1.147 + aRetName.Truncate(); 1.148 + 1.149 + int length = mHeaders.Length(); 1.150 + 1.151 + for (int i = 0; i < length; ++i) { 1.152 + if (mHeaders[i]->mId == ObexHeaderId::Name) { 1.153 + /* 1.154 + * According to section 2.2.2 [Name] of IrOBEX spec, we know that 1.155 + * the Name header is "a null terminated Unicode text string describing 1.156 + * the name of the object.", and that's the reason why we need to minus 1.157 + * 1 to get the real length of the file name. 1.158 + */ 1.159 + int nameLength = mHeaders[i]->mDataLength / 2 - 1; 1.160 + uint8_t* ptr = mHeaders[i]->mData.get(); 1.161 + 1.162 + for (int j = 0; j < nameLength; ++j) { 1.163 + char16_t c = ((((uint32_t)ptr[j * 2]) << 8) | ptr[j * 2 + 1]); 1.164 + aRetName += c; 1.165 + } 1.166 + 1.167 + break; 1.168 + } 1.169 + } 1.170 + } 1.171 + 1.172 + void GetContentType(nsString& aRetContentType) const 1.173 + { 1.174 + aRetContentType.Truncate(); 1.175 + 1.176 + int length = mHeaders.Length(); 1.177 + 1.178 + for (int i = 0; i < length; ++i) { 1.179 + if (mHeaders[i]->mId == ObexHeaderId::Type) { 1.180 + uint8_t* ptr = mHeaders[i]->mData.get(); 1.181 + aRetContentType.AssignASCII((const char*)ptr); 1.182 + break; 1.183 + } 1.184 + } 1.185 + } 1.186 + 1.187 + // @return file length, 0 means file length is unknown. 1.188 + void GetLength(uint32_t* aRetLength) const 1.189 + { 1.190 + int length = mHeaders.Length(); 1.191 + *aRetLength = 0; 1.192 + 1.193 + for (int i = 0; i < length; ++i) { 1.194 + if (mHeaders[i]->mId == ObexHeaderId::Length) { 1.195 + uint8_t* ptr = mHeaders[i]->mData.get(); 1.196 + *aRetLength = ((uint32_t)ptr[0] << 24) | 1.197 + ((uint32_t)ptr[1] << 16) | 1.198 + ((uint32_t)ptr[2] << 8) | 1.199 + ((uint32_t)ptr[3]); 1.200 + return; 1.201 + } 1.202 + } 1.203 + } 1.204 + 1.205 + void GetBodyLength(int* aRetBodyLength) const 1.206 + { 1.207 + int length = mHeaders.Length(); 1.208 + *aRetBodyLength = 0; 1.209 + 1.210 + for (int i = 0; i < length; ++i) { 1.211 + if (mHeaders[i]->mId == ObexHeaderId::Body || 1.212 + mHeaders[i]->mId == ObexHeaderId::EndOfBody) { 1.213 + *aRetBodyLength = mHeaders[i]->mDataLength; 1.214 + return; 1.215 + } 1.216 + } 1.217 + } 1.218 + 1.219 + void GetBody(uint8_t** aRetBody) const 1.220 + { 1.221 + int length = mHeaders.Length(); 1.222 + *aRetBody = nullptr; 1.223 + 1.224 + for (int i = 0; i < length; ++i) { 1.225 + if (mHeaders[i]->mId == ObexHeaderId::Body || 1.226 + mHeaders[i]->mId == ObexHeaderId::EndOfBody) { 1.227 + uint8_t* ptr = mHeaders[i]->mData.get(); 1.228 + *aRetBody = new uint8_t[mHeaders[i]->mDataLength]; 1.229 + memcpy(*aRetBody, ptr, mHeaders[i]->mDataLength); 1.230 + return; 1.231 + } 1.232 + } 1.233 + } 1.234 + 1.235 + bool Has(ObexHeaderId aId) const 1.236 + { 1.237 + int length = mHeaders.Length(); 1.238 + for (int i = 0; i < length; ++i) { 1.239 + if (mHeaders[i]->mId == aId) { 1.240 + return true; 1.241 + } 1.242 + } 1.243 + 1.244 + return false; 1.245 + } 1.246 + 1.247 + void ClearHeaders() 1.248 + { 1.249 + mHeaders.Clear(); 1.250 + } 1.251 + 1.252 +private: 1.253 + uint8_t mOpcode; 1.254 + nsTArray<nsAutoPtr<ObexHeader> > mHeaders; 1.255 +}; 1.256 + 1.257 +int AppendHeaderName(uint8_t* aRetBuf, int aBufferSize, const char* aName, 1.258 + int aLength); 1.259 +int AppendHeaderBody(uint8_t* aRetBuf, int aBufferSize, const uint8_t* aData, 1.260 + int aLength); 1.261 +int AppendHeaderEndOfBody(uint8_t* aRetBuf); 1.262 +int AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength); 1.263 +int AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId); 1.264 +void SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength); 1.265 + 1.266 +/** 1.267 + * @return true when the message was parsed without any error, false otherwise. 1.268 + */ 1.269 +bool ParseHeaders(const uint8_t* aHeaderStart, 1.270 + int aTotalLength, 1.271 + ObexHeaderSet* aRetHanderSet); 1.272 + 1.273 +END_BLUETOOTH_NAMESPACE 1.274 + 1.275 +#endif