* Patch from Ondrej Pokorny to allow correct nodefault/stored for strings

git-svn-id: trunk@37954 -
This commit is contained in:
michael 2018-01-13 10:22:16 +00:00
parent 29badfe5af
commit f6a08a2c74
5 changed files with 152 additions and 4 deletions

1
.gitattributes vendored
View File

@ -13441,6 +13441,7 @@ tests/test/tprocvar3.pp svneol=native#text/plain
tests/test/tprop.pp svneol=native#text/plain
tests/test/tprop1.pp svneol=native#text/plain
tests/test/tprop2.pp svneol=native#text/plain
tests/test/tpropdef.pp svneol=native#text/plain
tests/test/trange1.pp svneol=native#text/plain
tests/test/trange2.pp svneol=native#text/plain
tests/test/trange3.pp svneol=native#text/plain

View File

@ -205,6 +205,9 @@ interface
{# Returns true if p is a short string type }
function is_shortstring(p : tdef) : boolean;
{# Returns true if p is any pointer def }
function is_pointer(p : tdef) : boolean;
{# Returns true if p is a pchar def }
function is_pchar(p : tdef) : boolean;
@ -856,6 +859,12 @@ implementation
is_widechar(tarraydef(p).elementdef);
end;
{ true if p is any pointer def }
function is_pointer(p : tdef) : boolean;
begin
is_pointer:=(p.typ=pointerdef);
end;
{ true if p is a pchar def }
function is_pchar(p : tdef) : boolean;
begin

View File

@ -222,6 +222,15 @@ implementation
end;
end;
function has_implicit_default(p : tpropertysym) : boolean;
begin
has_implicit_default:=
(is_string(p.propdef) or
is_real(p.propdef) or
is_pointer(p.propdef));
end;
function allow_default_property(p : tpropertysym) : boolean;
begin
@ -656,6 +665,10 @@ implementation
end;
end;
end;
if has_implicit_default(p) then
begin
p.default:=0;
end;
if not is_record(astruct) and try_to_consume(_DEFAULT) then
begin
if not allow_default_property(p) then

View File

@ -944,7 +944,7 @@ begin
DefValue :=PPropInfo(PropInfo)^.Default;
DefFloatValue:=PSingle(@PPropInfo(PropInfo)^.Default)^;
end;
if (FloatValue<>DefFloatValue) or (DefValue=longint($80000000)) then
if (FloatValue<>DefFloatValue) or (not HasAncestor and (DefValue=longint($80000000))) then
begin
Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
WriteFloat(FloatValue);
@ -985,9 +985,12 @@ begin
if HasAncestor then
DefStrValue := GetStrProp(Ancestor, PropInfo)
else
begin
DefValue :=PPropInfo(PropInfo)^.Default;
SetLength(DefStrValue, 0);
end;
if StrValue <> DefStrValue then
if (StrValue<>DefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
begin
Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
if Assigned(FOnWriteStringProperty) then
@ -1002,9 +1005,12 @@ begin
if HasAncestor then
WDefStrValue := GetWideStrProp(Ancestor, PropInfo)
else
begin
DefValue :=PPropInfo(PropInfo)^.Default;
SetLength(WDefStrValue, 0);
end;
if WStrValue <> WDefStrValue then
if (WStrValue<>WDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
begin
Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
WriteWideString(WStrValue);
@ -1017,9 +1023,12 @@ begin
if HasAncestor then
UDefStrValue := GetUnicodeStrProp(Ancestor, PropInfo)
else
begin
DefValue :=PPropInfo(PropInfo)^.Default;
SetLength(UDefStrValue, 0);
end;
if UStrValue <> UDefStrValue then
if (UStrValue<>UDefStrValue) or (not HasAncestor and (DefValue=longint($80000000))) then
begin
Driver.BeginProperty(FPropPath + PPropInfo(PropInfo)^.Name);
WriteUnicodeString(UStrValue);

116
tests/test/tpropdef.pp Normal file
View File

@ -0,0 +1,116 @@
program EmptyStringWriter;
{$mode objfpc}{$h+}
uses
SysUtils, Classes;
type
TMyComp = class(TComponent)
public const
cDefS = 'default';
private
fS: string;
fT: string;
fU: string;
fSn: string;
fTn: string;
fUn: string;
fSdef: string;
function SStored: Boolean;
function SnStored: Boolean;
function SdefStored: Boolean;
public
constructor Create(AOwner: TComponent); override;
published
property S: string read fS write fS stored SStored nodefault;
property T: string read fT write fT nodefault;
property U: string read fU write fU;
property Sn: string read fSn write fSn stored SnStored nodefault;
property Tn: string read fTn write fTn nodefault;
property Un: string read fUn write fUn;
property Sdef: string read fSdef write fSdef stored SdefStored nodefault;
end;
{ TMyComp }
constructor TMyComp.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fS := cDefS;
fSn := cDefS;
fSdef := cDefS;
end;
function TMyComp.SdefStored: Boolean;
begin
Result := fSdef <> cDefS;
end;
function TMyComp.SnStored: Boolean;
begin
Result := fSn <> cDefS;
end;
function TMyComp.SStored: Boolean;
begin
Result := fS <> cDefS;
end;
const
ExpectedOutput: RawByteString = #7#84#77#121#67#111#109#112#0#1#83#6#0#1#84#6#0#2#83#110#6#1#110#2#84#110#6#1#110#2#85#110#6#1#110#0#0;
var
xStream: TStream;
xWriter: TWriter;
C: TMyComp;
xReader: TReader;
B: Byte;
I: Integer;
begin
xStream := TMemoryStream.Create;
C := TMyComp.Create(nil);
C.S := '';
C.T := '';
C.U := '';
C.Sn := 'n';
C.Tn := 'n';
C.Un := 'n';
//keep SDef to default value -> won't be streamed
xWriter := TWriter.Create(xStream, 1024);
xWriter.WriteComponent(C);
C.Free;
xWriter.Free;
xStream.Position := 0;
I := 1;
while xStream.Read(B, 1) = 1 do
begin
if (I>Length(ExpectedOutput)) or (B<>Ord(ExpectedOutput[I])) then
raise Exception.CreateFmt('Wrong output at character index: %d', [I]);
Inc(I);
end;
xStream.Position := 0;
C := TMyComp.Create(nil);
xReader := TReader.Create(xStream, 1024);
xReader.BeginReferences;
xReader.ReadComponent(C);
xReader.EndReferences;
if C.S<>'' then
raise Exception.Create('S invalid.');
if C.T<>'' then
raise Exception.Create('T invalid.');
if C.U<>'' then
raise Exception.Create('U invalid.');
if C.Sn<>'n' then
raise Exception.Create('Sn invalid.');
if C.Tn<>'n' then
raise Exception.Create('Tn invalid.');
if C.Un<>'n' then
raise Exception.Create('Un invalid.');
if C.Sdef<>TMyComp.cDefS then
raise Exception.Create('Un invalid.');
C.Free;
xReader.Free;
xStream.Free;
end.