{***************************************************************************** The DEC team (see file NOTICE.txt) 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. A copy of this licence is found in the root directory of this project in the file LICENCE.txt or alternatively 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 DECUtilRawByteStringHelper; interface {$INCLUDE DECOptions.inc} /// /// System.pas does not contain a RawByteString compatible version of this /// routine so we created our own, copying and adapting code from system.pas /// for the NextGen compiler and using a solution from Remy Lebeau for the /// Win32/Win64 compiler. /// /// /// String to be processed /// procedure UniqueString(var Str: RawByteString); implementation uses {$IFDEF FPC} SysUtils; {$ELSE} System.SysUtils; {$ENDIF} type // Duplicate of the System.pas internal declaration. Needs to be kept in sync. PStrRec = ^StrRec; StrRec = packed record {$IFDEF CPU64BITS} _Padding: Integer; // Make 16 byte align for payload.. {$ENDIF} codePage: Word; elemSize: Word; refCnt: Integer; length: Integer; end; function _NewAnsiString(CharLength: Integer; CodePage: Word): Pointer; var P: PStrRec; begin Result := nil; if CharLength > 0 then begin // Alloc an extra null for strings with even length. This has no actual // cost since the allocator will round up the request to an even size // anyway. All _WideStr allocations have even length, and need a double // null terminator. if CharLength >= MaxInt - SizeOf(StrRec) then raise EIntOverflow.Create( 'IntOverflow in _NewAnsiString. CharLength: ' + IntToStr(CharLength)); GetMem(P, CharLength + SizeOf(StrRec) + 1 + ((CharLength + 1) and 1)); Result := Pointer(PByte(P) + SizeOf(StrRec)); P.length := CharLength; P.refcnt := 1; if CodePage = 0 then {$IFDEF NEXTGEN} CodePage := Word(CP_UTF8); {$ELSE NEXTGEN} CodePage := Word(DefaultSystemCodePage); {$ENDIF NEXTGEN} P.codePage := CodePage; P.elemSize := 1; PWideChar(Result)[CharLength div 2] := #0; // length guaranteed >= 2 end; end; function _LStrClr(var S): Pointer; var P: PStrRec; begin if Pointer(S) <> nil then begin P := Pointer(PByte(S) - SizeOf(StrRec)); Pointer(S) := nil; if P.refCnt > 0 then begin {$IFDEF FPC} if InterlockedDecrement(P.refCnt) = 0 then {$ELSE} {$IF CompilerVersion >= 24.0} if AtomicDecrement(P.refCnt) = 0 then {$ELSE} Dec(P.refCnt); if (P.refCnt = 0) then {$IFEND} {$ENDIF} FreeMem(P); end; end; Result := @S; end; function InternalUniqueStringA(var Str: RawByteString): Pointer; var P: PStrRec; begin Result := Pointer(Str); if Result <> nil then begin Result := Pointer(Str); P := Pointer(PByte(Str) - sizeof(StrRec)); if P.refCnt <> 1 then begin Result := _NewAnsiString(P.length, P.codePage); Move(Pointer(Str)^, Pointer(Result)^, P.length); _LStrClr(Str); Pointer(Str) := Result; end; end; end; procedure UniqueString(var Str: RawByteString); begin InternalUniqueStringA(Str); end; end.