(* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *) unit Thrift.Utils; interface {$I Thrift.Defines.inc} uses {$IFDEF OLD_UNIT_NAMES} Classes, Windows, SysUtils, Character, SyncObjs; {$ELSE} System.Classes, Winapi.Windows, System.SysUtils, System.Character, System.SyncObjs; {$ENDIF} type IOverlappedHelper = interface ['{A1832EFA-2E02-4884-8F09-F0A0277157FA}'] function Overlapped : TOverlapped; function OverlappedPtr : POverlapped; function WaitHandle : THandle; function WaitFor(dwTimeout: DWORD) : DWORD; end; TOverlappedHelperImpl = class( TInterfacedObject, IOverlappedHelper) strict protected FOverlapped : TOverlapped; FEvent : TEvent; // IOverlappedHelper function Overlapped : TOverlapped; function OverlappedPtr : POverlapped; function WaitHandle : THandle; function WaitFor(dwTimeout: DWORD) : DWORD; public constructor Create; destructor Destroy; override; end; Base64Utils = class sealed public class function Encode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; static; class function Decode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; static; end; CharUtils = class sealed public class function IsHighSurrogate( const c : Char) : Boolean; static; inline; class function IsLowSurrogate( const c : Char) : Boolean; static; inline; end; function InterlockedCompareExchange64( var Target : Int64; Exchange, Comparand : Int64) : Int64; stdcall; function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64; stdcall; implementation { TOverlappedHelperImpl } constructor TOverlappedHelperImpl.Create; begin inherited Create; FillChar( FOverlapped, SizeOf(FOverlapped), 0); FEvent := TEvent.Create( nil, TRUE, FALSE, ''); // always ManualReset, see MSDN FOverlapped.hEvent := FEvent.Handle; end; destructor TOverlappedHelperImpl.Destroy; begin try FOverlapped.hEvent := 0; FreeAndNil( FEvent); finally inherited Destroy; end; end; function TOverlappedHelperImpl.Overlapped : TOverlapped; begin result := FOverlapped; end; function TOverlappedHelperImpl.OverlappedPtr : POverlapped; begin result := @FOverlapped; end; function TOverlappedHelperImpl.WaitHandle : THandle; begin result := FOverlapped.hEvent; end; function TOverlappedHelperImpl.WaitFor( dwTimeout : DWORD) : DWORD; begin result := WaitForSingleObject( FOverlapped.hEvent, dwTimeout); end; { Base64Utils } class function Base64Utils.Encode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; const ENCODE_TABLE : PAnsiChar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; begin ASSERT( len in [1..3]); dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff] shr 2) and $3F]); case len of 3 : begin Inc(dstOff); dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff] shl 4) and $30) or ((src[srcOff + 1] shr 4) and $0F)]); Inc(dstOff); dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff + 1] shl 2) and $3C) or ((src[srcOff + 2] shr 6) and $03)]); Inc(dstOff); dst[dstOff] := Byte( ENCODE_TABLE[ src[srcOff + 2] and $3F]); result := 4; end; 2 : begin Inc(dstOff); dst[dstOff] := Byte( ENCODE_TABLE[ ((src[srcOff] shl 4) and $30) or ((src[srcOff + 1] shr 4) and $0F)]); Inc(dstOff); dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff + 1] shl 2) and $3C]); result := 3; end; 1 : begin Inc(dstOff); dst[dstOff] := Byte( ENCODE_TABLE[ (src[srcOff] shl 4) and $30]); result := 2; end; else ASSERT( FALSE); result := 0; // because invalid call end; end; class function Base64Utils.Decode( const src : TBytes; srcOff, len : Integer; dst : TBytes; dstOff : Integer) : Integer; const DECODE_TABLE : array[0..$FF] of Integer = ( -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ); begin ASSERT( len in [1..4]); result := 1; dst[dstOff] := ((DECODE_TABLE[src[srcOff] and $0FF] shl 2) or (DECODE_TABLE[src[srcOff + 1] and $0FF] shr 4)); if (len > 2) then begin Inc( result); Inc( dstOff); dst[dstOff] := (((DECODE_TABLE[src[srcOff + 1] and $0FF] shl 4) and $F0) or (DECODE_TABLE[src[srcOff + 2] and $0FF] shr 2)); if (len > 3) then begin Inc( result); Inc( dstOff); dst[dstOff] := (((DECODE_TABLE[src[srcOff + 2] and $0FF] shl 6) and $C0) or DECODE_TABLE[src[srcOff + 3] and $0FF]); end; end; end; class function CharUtils.IsHighSurrogate( const c : Char) : Boolean; begin {$IF CompilerVersion < 23.0} result := Character.IsHighSurrogate( c); {$ELSE} result := c.IsHighSurrogate(); {$IFEND} end; class function CharUtils.IsLowSurrogate( const c : Char) : Boolean; begin {$IF CompilerVersion < 23.0} result := Character.IsLowSurrogate( c); {$ELSE} result := c.IsLowSurrogate; {$IFEND} end; // natively available since stone age function InterlockedCompareExchange64; external KERNEL32 name 'InterlockedCompareExchange64'; // natively available >= Vista // implemented this way since there are still some people running Windows XP :-( function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64; stdcall; var old : Int64; begin repeat Old := Addend; until (InterlockedCompareExchange64( Addend, Old + Value, Old) = Old); result := Old; end; end.