unit ObexParserUnit; interface uses System.SysUtils, System.Classes, System.Generics.Collections, Winapi.WinSock2; // ntohs, ntohl ÇÔ¼ö »ç¿ë // OBEX Çì´õ ID »ó¼ö const OBEX_HID_NAME = $01; OBEX_HID_BODY = $48; OBEX_HID_BODY_FINAL = $49; OBEX_HID_LENGTH = $C3; type { TObexHeader: ÆÄ½ÌµÈ °³º° Çì´õ (ID, Value)¸¦ ÀúÀå } TObexHeader = class public HeaderID: Byte; Value: TBytes; end; { TObexPacket: OBEX ÆÐŶ Àüü¸¦ ÆÄ½ÌÇÏ°í µ¥ÀÌÅ͸¦ º¸°ü } TObexPacket = class private FHeaders: TList; FOpcode: Byte; FPacketLength: Word; function GetHeader(HeaderID: Byte): TObexHeader; function GetBody: TBytes; function GetName: string; function GetTotalLength: Cardinal; public constructor Create; destructor Destroy; override; // ÀÌ ÇÔ¼ö°¡ »ç¿ëÀÚ°¡ ¿äûÇÑ "ij½ºÆÃ ÇÔ¼ö"ÀÔ´Ï´Ù. procedure Parse(Buffer: PByte; Size: Integer); // ÁÖ¿ä ¼Ó¼º property Opcode: Byte read FOpcode; property PacketLength: Word read FPacketLength; property Name: string read GetName; // 0x01 Çì´õ property TotalLength: Cardinal read GetTotalLength; // 0xC3 Çì´õ property Body: TBytes read GetBody; // 0x48 ¶Ç´Â 0x49 Çì´õ end; implementation { TObexPacket } constructor TObexPacket.Create; begin inherited; FHeaders := TList.Create; end; destructor TObexPacket.Destroy; var Header: TObexHeader; begin for Header in FHeaders do Header.Free; FHeaders.Free; inherited; end; function TObexPacket.GetHeader(HeaderID: Byte): TObexHeader; var Header: TObexHeader; begin Result := nil; for Header in FHeaders do begin if Header.HeaderID = HeaderID then Exit(Header); end; end; function TObexPacket.GetBody: TBytes; var Header: TObexHeader; begin // Body-Final (0x49)À» ¸ÕÀú ã°í, ¾øÀ¸¸é Body (0x48)¸¦ ãÀ½ Header := GetHeader(OBEX_HID_BODY_FINAL); if Header = nil then Header := GetHeader(OBEX_HID_BODY); if Header <> nil then Result := Header.Value else Result := nil; end; function TObexPacket.GetName: string; var Header: TObexHeader; begin Result := ''; Header := GetHeader(OBEX_HID_NAME); if (Header <> nil) and (Length(Header.Value) > 0) then begin // OBEX À̸§Àº UTF-16 Big Endian, ¸¶Áö¸· 2¹ÙÀÌÆ®´Â ³Î Á¾°á Result := TEncoding.BigEndianUnicode.GetString(Header.Value, 0, Length(Header.Value) - 2); end; end; function TObexPacket.GetTotalLength: Cardinal; var Header: TObexHeader; begin Result := 0; Header := GetHeader(OBEX_HID_LENGTH); if (Header <> nil) and (Length(Header.Value) = 4) then begin // 32ºñÆ® Big Endian (Network) °ªÀ» Host (Little Endian)·Î º¯È¯ Result := ntohl(PCardinal(Header.Value)^); end; end; procedure TObexPacket.Parse(Buffer: PByte; Size: Integer); var CurrentOffset: Integer; Header: TObexHeader; HeaderID: Byte; HeaderLen: Word; ValueLen: Integer; begin // ±âÁ¸ Çì´õ Ŭ¸®¾î for Header in FHeaders do Header.Free; FHeaders.Clear; if (Buffer = nil) or (Size < 3) then Exit; // ÃÖ¼Ò 3¹ÙÀÌÆ® (Opcode + PacketLength) FOpcode := Buffer[0]; // 16ºñÆ® Big Endian (Network) °ªÀ» Host (Little Endian)·Î º¯È¯ FPacketLength := ntohs(PWord(@Buffer[1])^); // ÆÐŶ Å©±â °ËÁõ if FPacketLength > Size then Exit; // ½ÇÁ¦ ¹öÆÛ Å©±âº¸´Ù ÆÐŶ ±æÀ̰¡ ´õ Å­ (À߸øµÈ µ¥ÀÌÅÍ) CurrentOffset := 3; // Çì´õ ½ÃÀÛ À§Ä¡ // Çì´õ ÆÄ½Ì ·çÇÁ while CurrentOffset < FPacketLength do begin Header := TObexHeader.Create; HeaderID := Buffer[CurrentOffset]; Header.HeaderID := HeaderID; Inc(CurrentOffset); // Çì´õ IDÀÇ »óÀ§ 2ºñÆ®·Î ŸÀÔÀ» ±¸ºÐ (01=À¯´ÏÄÚµå, 10=¹ÙÀÌÆ®½ÃÄö½º, 11=4¹ÙÀÌÆ®Á¤¼ö) case (HeaderID and $C0) of $00, // Name (0x01) $40: // Body (0x48, 0x49) begin // Çì´õ ±æÀÌ (2¹ÙÀÌÆ® Big Endian) if (CurrentOffset + 2) > FPacketLength then begin Header.Free; Break; end; HeaderLen := ntohs(PWord(@Buffer[CurrentOffset])^); Inc(CurrentOffset, 2); // [¼öÁ¤] Çì´õ ±æÀ̰¡ ÃÖ¼Ò 3¹ÙÀÌÆ®ÀÎÁö È®ÀÎ if HeaderLen < 3 then begin Header.Free; Break; end; // ½ÇÁ¦ °ª ±æÀÌ (Àüü Çì´õ ±æÀÌ - ID(1) - Length(2)) ValueLen := HeaderLen - 3; if (CurrentOffset + ValueLen) > FPacketLength then begin Header.Free; Break; // ÆÐŶÀÌ °ÅÁþ¸»À» Çϰí ÀÖÀ½ end; SetLength(Header.Value, ValueLen); Move(Buffer[CurrentOffset], Header.Value[0], ValueLen); Inc(CurrentOffset, ValueLen); end; $C0: // Length (0xC3) begin // 4¹ÙÀÌÆ® Á¤¼ö (°ª ÀÚü°¡ 4¹ÙÀÌÆ®) ValueLen := 4; SetLength(Header.Value, ValueLen); Move(Buffer[CurrentOffset], Header.Value[0], ValueLen); Inc(CurrentOffset, ValueLen); end else // ¾Ë ¼ö ¾ø´Â Çì´õ ŸÀÔ Break; end; FHeaders.Add(Header); end; end; end.