michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_dom_bluetooth_obexbase_h__ michael@0: #define mozilla_dom_bluetooth_obexbase_h__ michael@0: michael@0: #include "BluetoothCommon.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsTArray.h" michael@0: michael@0: BEGIN_BLUETOOTH_NAMESPACE michael@0: michael@0: const char FINAL_BIT = 0x80; michael@0: michael@0: /* michael@0: * Defined in section 2.1 "OBEX Headers", IrOBEX ver 1.2 michael@0: */ michael@0: enum ObexHeaderId { michael@0: Count = 0xC0, michael@0: Name = 0x01, michael@0: Type = 0x42, michael@0: Length = 0xC3, michael@0: TimeISO8601 = 0x44, michael@0: Time4Byte = 0xC4, michael@0: Description = 0x05, michael@0: Target = 0x46, michael@0: HTTP = 0x47, michael@0: Body = 0x48, michael@0: EndOfBody = 0x49, michael@0: Who = 0x4A, michael@0: ConnectionId = 0xCB, michael@0: AppParameters = 0x4C, michael@0: AuthChallenge = 0x4D, michael@0: AuthResponse = 0x4E, michael@0: ObjectClass = 0x4F michael@0: }; michael@0: michael@0: /* michael@0: * Defined in section 3.3 "OBEX Operations and Opcode definitions", michael@0: * IrOBEX ver 1.2 michael@0: */ michael@0: enum ObexRequestCode { michael@0: Connect = 0x80, michael@0: Disconnect = 0x81, michael@0: Put = 0x02, michael@0: PutFinal = 0x82, michael@0: Get = 0x03, michael@0: GetFinal = 0x83, michael@0: SetPath = 0x85, michael@0: Abort = 0xFF michael@0: }; michael@0: michael@0: /* michael@0: * Defined in section 3.2.1 "Response Code values", IrOBEX ver 1.2 michael@0: */ michael@0: enum ObexResponseCode { michael@0: Continue = 0x90, michael@0: michael@0: Success = 0xA0, michael@0: Created = 0xA1, michael@0: Accepted = 0xA2, michael@0: NonAuthoritativeInfo = 0xA3, michael@0: NoContent = 0xA4, michael@0: ResetContent = 0xA5, michael@0: PartialContent = 0xA6, michael@0: michael@0: MultipleChoices = 0xB0, michael@0: MovedPermanently = 0xB1, michael@0: MovedTemporarily = 0xB2, michael@0: SeeOther = 0xB3, michael@0: NotModified = 0xB4, michael@0: UseProxy = 0xB5, michael@0: michael@0: BadRequest = 0xC0, michael@0: Unauthorized = 0xC1, michael@0: PaymentRequired = 0xC2, michael@0: Forbidden = 0xC3, michael@0: NotFound = 0xC4, michael@0: MethodNotAllowed = 0xC5, michael@0: NotAcceptable = 0xC6, michael@0: ProxyAuthenticationRequired = 0xC7, michael@0: RequestTimeOut = 0xC8, michael@0: Conflict = 0xC9, michael@0: Gone = 0xCA, michael@0: LengthRequired = 0xCB, michael@0: PreconditionFailed = 0xCC, michael@0: RequestedEntityTooLarge = 0xCD, michael@0: RequestUrlTooLarge = 0xCE, michael@0: UnsupprotedMediaType = 0xCF, michael@0: michael@0: InternalServerError = 0xD0, michael@0: NotImplemented = 0xD1, michael@0: BadGateway = 0xD2, michael@0: ServiceUnavailable = 0xD3, michael@0: GatewayTimeout = 0xD4, michael@0: HttpVersionNotSupported = 0xD5, michael@0: michael@0: DatabaseFull = 0xE0, michael@0: DatabaseLocked = 0xE1, michael@0: }; michael@0: michael@0: class ObexHeader michael@0: { michael@0: public: michael@0: ObexHeader(ObexHeaderId aId, int aDataLength, const uint8_t* aData) michael@0: : mId(aId) michael@0: , mDataLength(aDataLength) michael@0: , mData(nullptr) michael@0: { michael@0: mData = new uint8_t[mDataLength]; michael@0: memcpy(mData, aData, aDataLength); michael@0: } michael@0: michael@0: ~ObexHeader() michael@0: { michael@0: } michael@0: michael@0: ObexHeaderId mId; michael@0: int mDataLength; michael@0: nsAutoArrayPtr mData; michael@0: }; michael@0: michael@0: class ObexHeaderSet michael@0: { michael@0: public: michael@0: ObexHeaderSet(uint8_t aOpcode) : mOpcode(aOpcode) michael@0: { michael@0: } michael@0: michael@0: ~ObexHeaderSet() michael@0: { michael@0: } michael@0: michael@0: void AddHeader(ObexHeader* aHeader) michael@0: { michael@0: mHeaders.AppendElement(aHeader); michael@0: } michael@0: michael@0: void GetName(nsString& aRetName) const michael@0: { michael@0: aRetName.Truncate(); michael@0: michael@0: int length = mHeaders.Length(); michael@0: michael@0: for (int i = 0; i < length; ++i) { michael@0: if (mHeaders[i]->mId == ObexHeaderId::Name) { michael@0: /* michael@0: * According to section 2.2.2 [Name] of IrOBEX spec, we know that michael@0: * the Name header is "a null terminated Unicode text string describing michael@0: * the name of the object.", and that's the reason why we need to minus michael@0: * 1 to get the real length of the file name. michael@0: */ michael@0: int nameLength = mHeaders[i]->mDataLength / 2 - 1; michael@0: uint8_t* ptr = mHeaders[i]->mData.get(); michael@0: michael@0: for (int j = 0; j < nameLength; ++j) { michael@0: char16_t c = ((((uint32_t)ptr[j * 2]) << 8) | ptr[j * 2 + 1]); michael@0: aRetName += c; michael@0: } michael@0: michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void GetContentType(nsString& aRetContentType) const michael@0: { michael@0: aRetContentType.Truncate(); michael@0: michael@0: int length = mHeaders.Length(); michael@0: michael@0: for (int i = 0; i < length; ++i) { michael@0: if (mHeaders[i]->mId == ObexHeaderId::Type) { michael@0: uint8_t* ptr = mHeaders[i]->mData.get(); michael@0: aRetContentType.AssignASCII((const char*)ptr); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // @return file length, 0 means file length is unknown. michael@0: void GetLength(uint32_t* aRetLength) const michael@0: { michael@0: int length = mHeaders.Length(); michael@0: *aRetLength = 0; michael@0: michael@0: for (int i = 0; i < length; ++i) { michael@0: if (mHeaders[i]->mId == ObexHeaderId::Length) { michael@0: uint8_t* ptr = mHeaders[i]->mData.get(); michael@0: *aRetLength = ((uint32_t)ptr[0] << 24) | michael@0: ((uint32_t)ptr[1] << 16) | michael@0: ((uint32_t)ptr[2] << 8) | michael@0: ((uint32_t)ptr[3]); michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void GetBodyLength(int* aRetBodyLength) const michael@0: { michael@0: int length = mHeaders.Length(); michael@0: *aRetBodyLength = 0; michael@0: michael@0: for (int i = 0; i < length; ++i) { michael@0: if (mHeaders[i]->mId == ObexHeaderId::Body || michael@0: mHeaders[i]->mId == ObexHeaderId::EndOfBody) { michael@0: *aRetBodyLength = mHeaders[i]->mDataLength; michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void GetBody(uint8_t** aRetBody) const michael@0: { michael@0: int length = mHeaders.Length(); michael@0: *aRetBody = nullptr; michael@0: michael@0: for (int i = 0; i < length; ++i) { michael@0: if (mHeaders[i]->mId == ObexHeaderId::Body || michael@0: mHeaders[i]->mId == ObexHeaderId::EndOfBody) { michael@0: uint8_t* ptr = mHeaders[i]->mData.get(); michael@0: *aRetBody = new uint8_t[mHeaders[i]->mDataLength]; michael@0: memcpy(*aRetBody, ptr, mHeaders[i]->mDataLength); michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool Has(ObexHeaderId aId) const michael@0: { michael@0: int length = mHeaders.Length(); michael@0: for (int i = 0; i < length; ++i) { michael@0: if (mHeaders[i]->mId == aId) { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void ClearHeaders() michael@0: { michael@0: mHeaders.Clear(); michael@0: } michael@0: michael@0: private: michael@0: uint8_t mOpcode; michael@0: nsTArray > mHeaders; michael@0: }; michael@0: michael@0: int AppendHeaderName(uint8_t* aRetBuf, int aBufferSize, const char* aName, michael@0: int aLength); michael@0: int AppendHeaderBody(uint8_t* aRetBuf, int aBufferSize, const uint8_t* aData, michael@0: int aLength); michael@0: int AppendHeaderEndOfBody(uint8_t* aRetBuf); michael@0: int AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength); michael@0: int AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId); michael@0: void SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength); michael@0: michael@0: /** michael@0: * @return true when the message was parsed without any error, false otherwise. michael@0: */ michael@0: bool ParseHeaders(const uint8_t* aHeaderStart, michael@0: int aTotalLength, michael@0: ObexHeaderSet* aRetHanderSet); michael@0: michael@0: END_BLUETOOTH_NAMESPACE michael@0: michael@0: #endif