浏览代码

Merge branch 'develop'

Unknown 7 年之前
父节点
当前提交
852c05bacf

+ 234 - 0
Quick.AutoMapper.pas

@@ -0,0 +1,234 @@
+{ ***************************************************************************
+
+  Copyright (c) 2015-2018 Kike Pérez
+
+  Unit        : Quick.AutoMapper
+  Description : Auto Mapper object properties
+  Author      : Kike Pérez
+  Version     : 1.0
+  Created     : 25/08/2018
+  Modified    : 30/08/2018
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed 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 Quick.AutoMapper;
+
+interface
+
+uses
+  SysUtils,
+  Generics.Collections,
+  {$IFDEF FPC}
+  typinfo,
+  {$ENDIF}
+  RTTI;
+
+type
+
+  TCustomMapping = class
+  private
+    fMapDictionary : TDictionary<string,string>;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure AddMap(const aName, aMapName : string);
+    function GetMap(const aName : string; out vMapName : string) : Boolean;
+  end;
+
+  TObjMapper = class
+  public
+    class procedure Map(aSrcObj : TObject; aTgtObj : TObject; aCustomMapping: TCustomMapping = nil);
+  end;
+
+  TMapper<T : class, constructor> = class
+  public
+    class function Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil): T; overload;
+    class procedure Map(aSrcObj : TObject; aTgtObj : T; aCustomMapping : TCustomMapping = nil); overload;
+  end;
+
+  TAutoMapper<TClass1, TClass2 : class, constructor> = class
+  private
+    fCustomMapping : TCustomMapping;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    property CustomMapping : TCustomMapping read fCustomMapping write fCustomMapping;
+    function Map(aSrcObj : TClass1) : TClass2; overload;
+    {$IFNDEF FPC}
+    function Map(aSrcObj : TClass2) : TClass1; overload;
+    {$ELSE}
+    //freepascal detects overload with generic types as duplicated function, added dummy field to avoid this
+    function Map(aSrcObj : TClass2; dummy : Boolean = True) : TClass1; overload;
+    {$ENDIF}
+  end;
+
+  EAutoMapperError = class(Exception);
+
+implementation
+
+{ TObjMapper }
+
+class procedure TObjMapper.Map(aSrcObj : TObject; aTgtObj : TObject; aCustomMapping: TCustomMapping = nil);
+var
+  ctx : TRttiContext;
+  rType : TRttiType;
+  tgtprop : TRttiProperty;
+  mapname : string;
+  obj : TObject;
+begin
+  if aTgtObj = nil then aTgtObj := aTgtObj.ClassType.Create;
+
+  for tgtprop in ctx.GetType(aTgtObj.ClassInfo).GetProperties do
+  begin
+    if tgtprop.IsWritable then
+    begin
+      if not tgtprop.PropertyType.IsInstance then
+      begin
+        rType := ctx.GetType(aSrcObj.ClassInfo);
+        if Assigned(aCustomMapping) then
+        begin
+          if aCustomMapping.GetMap(tgtprop.Name,mapname) then
+          begin
+            if rType.GetProperty(mapname) = nil then raise EAutoMapperError.CreateFmt('No valid custom mapping (Source: %s - Target: %s)',[mapname,tgtprop.Name]);
+            {$IFNDEF FPC}
+            tgtprop.SetValue(aTgtObj,rType.GetProperty(mapname).GetValue(aSrcObj))
+            {$ELSE}
+            SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,mapname));
+            {$ENDIF}
+          end
+          else
+          begin
+            if rType.GetProperty(tgtprop.Name) <> nil then
+            try
+              {$IFNDEF FPC}
+              tgtprop.SetValue(aTgtObj,rType.GetProperty(tgtprop.Name).GetValue(aSrcObj));
+              {$ELSE}
+              SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,tgtprop.Name));
+              {$ENDIF}
+            except
+              on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
+            end;
+          end;
+        end
+        else
+        begin
+          try
+            {$IFNDEF FPC}
+            if rType.GetProperty(tgtprop.Name) <> nil then tgtprop.SetValue(aTgtObj,rType.GetProperty(tgtprop.Name).GetValue(aSrcObj));
+            {$ELSE}
+            if rType.GetProperty(tgtprop.Name) <> nil then SetPropValue(aTgtObj,tgtprop.Name,GetPropValue(aSrcObj,tgtprop.Name));
+            {$ENDIF}
+          except
+            on E : Exception do raise EAUtoMapperError.CreateFmt('Error mapping property "%s" : %s',[tgtprop.Name,e.message]);
+          end;
+        end;
+      end
+      else
+      begin
+        obj := tgtprop.GetValue(aTgtObj).AsObject;
+        {$IFNDEF FPC}
+        if obj = nil then obj := TObject.Create;
+        {$ELSE}
+        if obj = nil then obj := GetObjectProp(aSrcObj,tgtprop.Name).ClassType.Create;
+        {$ENDIF}
+
+        if obj <> nil then
+        begin
+          {$IFNDEF FPC}
+          TObjMapper.Map(rType.GetProperty(tgtprop.Name).GetValue(aSrcObj).AsObject,obj,aCustomMapping);
+          {$ELSE}
+          TObjMapper.Map(GetObjectProp(aSrcObj,tgtprop.Name),obj,aCustomMapping);
+          SetObjectProp(aTgtObj,tgtprop.Name,obj);
+          {$ENDIF}
+        end
+        else raise EAutoMapperError.CreateFmt('Target object "%s" not autocreated by class',[tgtprop.Name]);
+      end;
+    end;
+  end;
+end;
+
+class function TMapper<T>.Map(aSrcObj : TObject; aCustomMapping: TCustomMapping = nil) : T;
+var
+  obj : T;
+begin
+  obj := T.Create;
+  TObjMapper.Map(aSrcObj,obj,aCustomMapping);
+  Result := obj;
+end;
+
+class procedure TMapper<T>.Map(aSrcObj : TObject; aTgtObj : T; aCustomMapping : TCustomMapping = nil);
+begin
+  TObjMapper.Map(aSrcObj, aTgtObj, aCustomMapping);
+end;
+
+{ TAutoMapper<TClass1, TClass2> }
+
+constructor TAutoMapper<TClass1, TClass2>.Create;
+begin
+  fCustomMapping := TCustomMapping.Create;
+end;
+
+destructor TAutoMapper<TClass1, TClass2>.Destroy;
+begin
+  if Assigned(fCustomMapping) then fCustomMapping.Free;
+  inherited;
+end;
+
+{}
+function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass1): TClass2;
+begin
+  Result := TMapper<TClass2>.Map(aSrcObj,fCustomMapping);
+end;
+
+{$IFNDEF FPC}
+function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass2): TClass1;
+{$ELSE}
+function TAutoMapper<TClass1, TClass2>.Map(aSrcObj: TClass2; dummy : Boolean = True): TClass1;
+{$ENDIF}
+begin
+  Result := TMapper<TClass1>.Map(aSrcObj,fCustomMapping);
+end;
+
+{ TCustomMappingFields }
+
+procedure TCustomMapping.AddMap(const aName, aMapName: string);
+begin
+  //add map fields
+  fMapDictionary.Add(aName,aMapName);
+  //add reverse lookup
+  fMapDictionary.Add(aMapName,aName);
+end;
+
+constructor TCustomMapping.Create;
+begin
+  fMapDictionary := TDictionary<string,string>.Create;
+end;
+
+destructor TCustomMapping.Destroy;
+begin
+  fMapDictionary.Free;
+  inherited;
+end;
+
+function TCustomMapping.GetMap(const aName: string; out vMapName: string): Boolean;
+begin
+  Result := fMapDictionary.TryGetValue(aName,vMapName);
+end;
+
+end.

+ 17 - 4
Quick.Base64.pas

@@ -3,11 +3,11 @@
   Copyright (c) 2016-2017 Kike Pérez
 
   Unit        : Quick.Base64
-  Description : Log Api Redis Provider
+  Description : Base64 functions
   Author      : Kike Pérez
   Version     : 1.1
   Created     : 08/11/2017
-  Modified    : 07/05/2018
+  Modified    : 14/08/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -28,13 +28,17 @@
  *************************************************************************** }
 unit Quick.Base64;
 
-interface
-
 {$i QuickLib.inc}
 
+interface
+
 uses
+  {$IFDEF DELPHIXE7_UP}
+  System.NetEncoding;
+  {$ELSE}
   IdCoderMIME,
   IdGlobal;
+  {$ENDIF}
 
 function Base64Encode(const Input: string): string;
 function Base64Decode(const Input: string): string;
@@ -43,12 +47,21 @@ implementation
 
 function Base64Encode(const Input: string): string;
 begin
+  {$IFDEF DELPHIXE7_UP}
+  Result := TNetEncoding.Base64.Encode(Input);
+  {$ELSE}
   Result := TIdEncoderMIME.EncodeString(Input,IndyTextEncoding_OSDefault);
+  {$ENDIF}
 end;
 
 function Base64Decode(const Input: string): string;
 begin
+  {$IFDEF DELPHIXE7_UP}
+  Result := TNetEncoding.Base64.Decode(Input);
+  {$ELSE}
   Result := TIdDecoderMIME.DecodeString(Input,IndyTextEncoding_OSDefault);
+  {$ENDIF}
 end;
 
 end.
+

+ 81 - 51
Quick.Commons.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.Commons
   Description : Common functions
   Author      : Kike Pérez
-  Version     : 1.4
+  Version     : 1.5
   Created     : 14/07/2017
-  Modified    : 16/05/2018
+  Modified    : 13/08/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -50,6 +50,12 @@ interface
     {$ELSE}
     IOUtils,
     {$ENDIF}
+    {$IFDEF ANDROID}
+    Androidapi.JNI.Os,
+    Androidapi.Helpers,
+    Androidapi.JNI.JavaTypes,
+    Androidapi.JNI.GraphicsContentViewText,
+    {$ENDIF}
     DateUtils;
 
 type
@@ -641,42 +647,50 @@ end;
 
 function GetLoggedUserName : string;
 {$IFDEF MSWINDOWS}
-const
-  cnMaxUserNameLen = 254;
-var
-  sUserName     : string;
-  dwUserNameLen : DWord;
-begin
-  dwUserNameLen := cnMaxUserNameLen-1;
-  SetLength( sUserName, cnMaxUserNameLen );
-  GetUserName(PChar( sUserName ),dwUserNameLen );
-  SetLength( sUserName, dwUserNameLen );
-  Result := sUserName;
-end;
-{$ENDIF}
-{$IF DEFINED(FPC) AND DEFINED(LINUX)}
-begin
-  Result := GetEnvironmentVariable('USERNAME');
-end;
-
+  const
+    cnMaxUserNameLen = 254;
+  var
+    sUserName     : string;
+    dwUserNameLen : DWord;
+  begin
+    dwUserNameLen := cnMaxUserNameLen-1;
+    SetLength( sUserName, cnMaxUserNameLen );
+    GetUserName(PChar( sUserName ),dwUserNameLen );
+    SetLength( sUserName, dwUserNameLen );
+    Result := sUserName;
+  end;
+{$ELSE}
+  {$IF DEFINED(FPC) AND DEFINED(LINUX)}
+  begin
+    Result := GetEnvironmentVariable('USERNAME');
+  end;
+  {$ELSE}
+  begin
+    raise ENotImplemented.Create('Not Android GetLoggedUserName implemented!');
+  end;
+  {$ENDIF}
 {$ENDIF}
 
 function GetComputerName : string;
 {$IFDEF MSWINDOWS}
-var
-  dwLength: dword;
-begin
-  dwLength := 253;
-  SetLength(Result, dwLength+1);
-  if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
-  Result := pchar(result);
-end;
-{$ENDIF}
-{$IF DEFINED(FPC) AND DEFINED(LINUX)}
-begin
-  Result := GetEnvironmentVariable('COMPUTERNAME');
-end;
-
+  var
+    dwLength: dword;
+  begin
+    dwLength := 253;
+    SetLength(Result, dwLength+1);
+    if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
+    Result := pchar(result);
+  end;
+{$ELSE}
+  {$IF DEFINED(FPC) AND DEFINED(LINUX)}
+  begin
+    Result := GetEnvironmentVariable('COMPUTERNAME');
+  end;
+  {$ELSE} //Android gets model name
+  begin
+    Result := JStringToString(TJBuild.JavaClass.MODEL);
+  end;
+  {$ENDIF}
 {$ENDIF}
 
 function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
@@ -790,14 +804,22 @@ begin
   end
   else Result := '';
 end;
-{$ENDIF}
-{$IF DEFINED(FPC) AND DEFINED(LINUX)}
-var
-  version : TProgramVersion;
-begin
-  if GetProgramVersion(version) then Result := Format('%d.%d', [version.Major, version.Minor])
-    else Result := '';
-end;
+{$ELSE}
+  {$IF DEFINED(FPC) AND DEFINED(LINUX)}
+  var
+    version : TProgramVersion;
+  begin
+    if GetProgramVersion(version) then Result := Format('%d.%d', [version.Major, version.Minor])
+      else Result := '';
+  end;
+  {$ELSE}
+  var
+    PkgInfo : JPackageInfo;
+  begin
+    PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
+    Result := IntToStr(PkgInfo.VersionCode);
+  end;
+  {$ENDIF}
 {$ENDIF}
 
 function GetAppVersionFullStr: string;
@@ -844,14 +866,22 @@ begin
      LongRec(FixedPtr.dwFileVersionLS).Lo]); //build
   end;
 end;
-{$ENDIF}
-{$IF DEFINED(FPC) AND DEFINED(LINUX)}
-var
-  version : TProgramVersion;
-begin
-  if GetProgramVersion(version) then Result := Format('%d.%d.%d.%d', [version.Major, version.Minor, version.Revision, version.Build])
-    else Result := '';
-end;
+{$ELSE}
+  {$IF DEFINED(FPC) AND DEFINED(LINUX)}
+  var
+    version : TProgramVersion;
+  begin
+    if GetProgramVersion(version) then Result := Format('%d.%d.%d.%d', [version.Major, version.Minor, version.Revision, version.Build])
+      else Result := '';
+  end;
+  {$ELSE}
+  var
+    PkgInfo : JPackageInfo;
+  begin
+    PkgInfo := SharedActivity.getPackageManager.getPackageInfo(SharedActivity.getPackageName,0);
+    Result := JStringToString(PkgInfo.versionName);
+  end;
+  {$ENDIF}
 {$ENDIF}
 
 function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
@@ -1037,8 +1067,8 @@ begin
 end;
 {$ENDIF}
 
-initialization
 {$IFDEF MSWINDOWS}
+initialization
   try
     GetEnvironmentPaths;
   except

+ 85 - 0
Quick.Compression.pas

@@ -0,0 +1,85 @@
+{ ***************************************************************************
+
+  Copyright (c) 2016-2017 Kike Pérez
+
+  Unit        : Quick.Compression
+  Description : Compression functions
+  Author      : Kike Pérez
+  Version     : 1.1
+  Created     : 14/08/2018
+  Modified    : 20/08/2018
+
+  This file is part of QuickLib: https://github.com/exilon/QuickLib
+
+ ***************************************************************************
+
+  Licensed 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 Quick.Compression;
+
+{$i QuickLib.inc}
+
+interface
+
+uses
+  Classes,
+  System.SysUtils,
+  System.ZLib;
+
+  function CompressString(const aStr : string) : string;
+  function DecompressString(const aStr: string) : string;
+
+implementation
+
+function CompressString(const aStr : string) : string;
+var
+  strstream : TStringStream;
+  zipstream : TStringStream;
+begin
+  strstream := TStringStream.Create(aStr,TEncoding.UTF8);
+  try
+    zipstream := TStringStream.Create('',TEncoding.ANSI);
+    try
+      ZCompressStream(strstream, zipstream);
+      zipstream.Position := 0;
+      Result := zipstream.DataString;
+    finally
+      zipstream.Free;
+    end;
+  finally
+    strstream.Free;
+  end;
+end;
+
+function DecompressString(const aStr: string) : string;
+var
+  strstream : TStringStream;
+  zipstream : TStringStream;
+begin
+  zipstream := TStringStream.Create(aStr,TEncoding.ANSI);
+  try
+    strstream := TStringStream.Create('',TEncoding.UTF8);
+    try
+      ZDecompressStream(zipstream, strstream);
+      strstream.Position := 0;
+      Result := strstream.DataString;
+    finally
+      strstream.Free;
+    end;
+  finally
+    zipstream.Free;
+  end;
+end;
+
+end.

+ 10 - 4
Quick.Format.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.4
   Created     : 14/07/2017
-  Modified    : 07/04/2018
+  Modified    : 19/07/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -60,12 +60,18 @@ const
 var
   i : Integer;
   bfmt : string;
+  cspace : Char;
 begin
   i := 0;
   while aBytes > Power(1024, i + 1) do Inc(i);
-  if Spaced then bfmt := '%.2f %s'
-    else bfmt := '%.2f%s';
-  Result := Format(bfmt,[aBytes / IntPower(1024, i),mesure[i]]);
+  if Spaced then cspace := Char(32)
+    else cspace := Char(0);
+    // bfmt := '%.2f %s'
+    //else bfmt := '%.2f%s';
+  if i < 2 then bfmt := '%.0f%s%s'
+    else bfmt := '%.2f%s%s';
+
+  Result := Format(bfmt,[aBytes / IntPower(1024, i),cspace,mesure[i]]);
 end;
 
 

+ 32 - 15
Quick.JSONRecord.pas

@@ -5,9 +5,9 @@
   Unit        : Quick.JSONRecord
   Description : Serializable class
   Author      : Kike Pérez
-  Version     : 1.0
+  Version     : 1.1
   Created     : 05/05/2018
-  Modified    : 08/07/2018
+  Modified    : 28/08/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -34,7 +34,7 @@ interface
 
 uses
   Quick.Json.Serializer,
-  Rest.Json.Types;
+  Quick.AutoMapper;
 
 type
 
@@ -42,12 +42,19 @@ type
   ['{AF71F59C-89A5-4BFB-8227-0CC3068B7671}']
     procedure FromJson(const aJson : string);
     function ToJson : string;
+    procedure MapTo(aTgtObj : TObject);
+    procedure MapFrom(aSrcObj : TObject);
   end;
 
   TJsonRecord = class(TInterfacedObject,IJsonable)
+  public
     constructor CreateFromJson(const aJson : string);
     procedure FromJson(const aJson : string);
     function ToJson : string;
+    function Map<T : class, constructor> : T;
+    procedure MapTo(aTgtObj : TObject);
+    procedure MapFrom(aSrcObj : TObject);
+    function Clone : TObject; virtual;
   end;
 
 implementation
@@ -58,11 +65,8 @@ constructor TJsonRecord.CreateFromJson(const aJson: string);
 var
   serializer : TJsonSerializer;
 begin
-  {$IFNDEF FPC}
+  //inherited Create;
   serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
-  {$ELSE}
-  serializer := TJsonSerializer.Create;
-  {$ENDIF}
   try
     serializer.JsonToObject(Self,aJson);
   finally
@@ -74,11 +78,7 @@ procedure TJsonRecord.FromJson(const aJson: string);
 var
   serializer : TJsonSerializer;
 begin
-  {$IFNDEF FPC}
   serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
-  {$ELSE}
-  serializer := TJsonSerializer.Create;
-  {$ENDIF}
   try
     serializer.JsonToObject(Self,aJson);
   finally
@@ -86,15 +86,26 @@ begin
   end;
 end;
 
+function TJsonRecord.Map<T> : T;
+begin
+  Result := TMapper<T>.Map(Self);
+end;
+
+procedure TJsonRecord.MapFrom(aSrcObj: TObject);
+begin
+  TObjMapper.Map(aSrcObj,Self);
+end;
+
+procedure TJsonRecord.MapTo(aTgtObj: TObject);
+begin
+  TObjMapper.Map(Self,aTgtObj);
+end;
+
 function TJsonRecord.ToJson: string;
 var
   serializer : TJsonSerializer;
 begin
-  {$IFNDEF FPC}
   serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
-  {$ELSE}
-  serializer := TJsonSerializer.Create;
-  {$ENDIF}
   try
     Result := serializer.ObjectToJson(Self);
   finally
@@ -102,4 +113,10 @@ begin
   end;
 end;
 
+function TJsonRecord.Clone : TObject;
+begin
+  Result := Self.ClassType.Create;
+  TObjMapper.Map(Self,Result);
+end;
+
 end.

+ 13 - 4
Quick.Json.Serializer.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.2
   Created     : 21/05/2018
-  Modified    : 08/07/2018
+  Modified    : 28/08/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -379,6 +379,9 @@ end;
 
 constructor TJsonSerializer.Create(aSerializeLevel: TSerializeLevel);
 begin
+  {$IFDEF FPC}
+  if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EJsonSerializeError.Create('FreePascal RTTI only supports published properties');
+  {$ENDIF}
   fSerializeLevel := aSerializeLevel;
 end;
 
@@ -587,7 +590,9 @@ begin
       else
         begin
           {$IFNDEF FPC}
-          rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToJSON);
+          //avoid return unicode escaped chars if string
+          if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.JsonString.ToString)
+            else rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToJSON);
           {$ELSE}
           rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aName,member.ToJSON);
           if not rValue.IsEmpty then SetPropertyValue(aObject,aName,rValue);
@@ -791,11 +796,13 @@ begin
     tkFloat : Result := GetFloatProp(Instance,PropertyName);
     tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
     {$IFDEF FPC}
+    tkWString : Result := GetWideStrProp(Instance,PropertyName);
     tkSString,
     tkAString,
+    {$ELSE}
+    tkWString,
     {$ENDIF}
     tkLString : Result := GetStrProp(Instance,pinfo);
-    tkWString : Result := GetWideStrProp(Instance,PropertyName);
     {$IFDEF FPC}
     tkEnumeration : Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName));
     {$ELSE}
@@ -828,11 +835,13 @@ begin
     tkFloat : SetFloatProp(Instance,aPropInfo,aValue.AsExtended);
     tkChar : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
     {$IFDEF FPC}
+    tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
     tkSString,
     tkAString,
+    {$ELSE}
+    tkWString,
     {$ENDIF}
     tkLString : SetStrProp(Instance,aPropInfo,aValue.AsString);
-    tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
     {$IFDEF FPC}
     tkBool : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
     tkSet : LoadSetProperty(Instance,aPropInfo,aValue.AsString);

+ 2 - 2
Quick.Json.fpc.Compatibility.pas

@@ -24,7 +24,7 @@ type
 
   { TJsonArray }
 
-  TJsonArrayEx = class(fpjson.TJSONArray)
+  TJsonArray = class(fpjson.TJSONArray)
   public
     procedure AddElement(aValue : TJsonData);
   end;
@@ -65,7 +65,7 @@ implementation
 
 { TJsonArray }
 
-procedure TJsonArrayEx.AddElement(aValue: TJsonData);
+procedure TJsonArray.AddElement(aValue: TJsonData);
 begin
   Add(aValue);
 end;

+ 2 - 2
Quick.Service.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Version     : 1.1
   Created     : 14/07/2017
-  Modified    : 07/04/2018
+  Modified    : 30/08/2018
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
@@ -147,7 +147,7 @@ begin
         begin
           if QueryServiceStatus(svcHnd,svcStatus) then
           begin
-            while svcStatus.dwCurrentState <> SERVICE_RUNNING do
+            while svcStatus.dwCurrentState = SERVICE_START_PENDING do
             begin
               dwChkP := svcStatus.dwCheckPoint;
               Sleep(svcStatus.dwWaitHint);

+ 13 - 1
quicklib.lpk

@@ -16,7 +16,7 @@
       </Parsing>
     </CompilerOptions>
     <Version Major="1"/>
-    <Files Count="16">
+    <Files Count="19">
       <Item1>
         <Filename Value="Quick.Console.pas"/>
         <UnitName Value="Quick.Console"/>
@@ -81,6 +81,18 @@
         <Filename Value="Quick.Config.Provider.Json.pas"/>
         <UnitName Value="Quick.Config.Provider.Json"/>
       </Item16>
+      <Item17>
+        <Filename Value="Quick.Config.Provider.Registry.pas"/>
+        <UnitName Value="Quick.Config.Provider.Registry"/>
+      </Item17>
+      <Item18>
+        <Filename Value="Quick.Json.fpc.Compatibility.pas"/>
+        <UnitName Value="Quick.Json.fpc.Compatibility"/>
+      </Item18>
+      <Item19>
+        <Filename Value="Quick.JSONRecord.pas"/>
+        <UnitName Value="Quick.JSONRecord"/>
+      </Item19>
     </Files>
     <RequiredPkgs Count="3">
       <Item1>

+ 2 - 1
quicklib.pas

@@ -11,7 +11,8 @@ uses
   Quick.Console, Quick.AppService, Quick.Base64, Quick.Chrono, Quick.Commons, 
   Quick.FileMonitor, Quick.Files, Quick.Format, Quick.Log, Quick.Network, 
   Quick.Process, Quick.Service, Quick.SMTP, Quick.Threads, Quick.Config, 
-  Quick.Config.Provider.Json;
+  Quick.Config.Provider.Json, Quick.Config.Provider.Registry, 
+  Quick.Json.fpc.Compatibility, Quick.JSONRecord;
 
 implementation
 

+ 175 - 0
samples/delphi/QuickAutoMapper/AutoMappingObjects.dpr

@@ -0,0 +1,175 @@
+program AutoMappingObjects;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+  System.SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.JSONRecord,
+  Quick.AutoMapper;
+
+type
+
+  TJob = record
+    Name : string;
+    DateFrom : TDateTime;
+    DateTo : TDateTime;
+  end;
+
+  TCarType = (ctOil, ctDiesel);
+
+  TCar = class
+  private
+    fModel : string;
+    fCarType : TCarType;
+  published
+    property Model : string read fModel write fModel;
+    property CarType : TCarType read fCarType write fCarType;
+  end;
+
+  TUserBase = class(TJsonRecord)
+  private
+    fName : string;
+    fAge : Integer;
+    fCreationDate : TDateTime;
+    fNumbers : TArray<Integer>;
+  published
+    property Name : string read fName write fName;
+    property Age : Integer read fAge write fAge;
+    property CreationDate : TDateTime read fCreationDate write fCreationDate;
+    property Numbers : TArray<Integer> read fNumbers write fNumbers;
+  end;
+
+  TUser = class(TUserBase)
+  private
+    fId : Int64;
+    fCash : Integer;
+    fJob : TJob;
+    fCar : TCar;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  published
+    property Id : Int64 read fId write fId;
+    property Cash : Integer read fCash write fCash;
+    property Job : TJob read fJob write fJob;
+    property Car : TCar read fCar write fCar;
+  end;
+
+  TUser2 = class(TUserBase)
+  private
+    fIdUser : Int64;
+    fName : string;
+    fAge : Integer;
+    fNumbers : TArray<Integer>;
+    fJob : TJob;
+    fMoney : Integer;
+    fCar : TCar;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  published
+    property IdUser : Int64 read fIdUser write fIdUser;
+    property Name : string read fName write fName;
+    property Age : Integer read fAge write fAge;
+    property Numbers : TArray<Integer> read fNumbers write fNumbers;
+    property Money : Integer read fMoney write fMoney;
+    property Job : TJob read fJob write fJob;
+    property Car : TCar read fCar write fCar;
+  end;
+
+var
+  User : TUser;
+  User2 : TUser2;
+  UserClone : TUser;
+  job : TJob;
+  AutoMapper : TAutoMapper<TUser,TUser2>;
+
+{ TUser }
+
+constructor TUser.Create;
+begin
+  fCar := TCar.Create;
+end;
+
+destructor TUser.Destroy;
+begin
+  fCar.Free;
+  inherited;
+end;
+
+{ TUser2 }
+
+constructor TUser2.Create;
+begin
+  fCar := TCar.Create;
+end;
+
+destructor TUser2.Destroy;
+begin
+  fCar.Free;
+  inherited;
+end;
+
+begin
+  ReportMemoryLeaksOnShutdown := True;
+  try
+    User := TUser.Create;
+    User.Id := 17;
+    User.CreationDate := Now();
+    User.Name := 'Juan';
+    User.Age := 30;
+    User.Numbers := [1,2,3,4,5];
+    User.Cash := 3500;
+    job.Name := 'Designer';
+    job.DateFrom := IncMonth(Now(),-12);
+    job.DateTo := Now();
+    User.Job := job;
+    User.Car.Model := 'Ferrari';
+    User.Car.CarType := ctOil;
+    //User2 := TMapper<TUser2>.Map(User);
+    AutoMapper := TAutoMapper<TUser,TUser2>.Create;
+    try
+      AutoMapper.CustomMapping.AddMap('Cash','Money');
+      AutoMapper.CustomMapping.AddMap('Id','IdUser');
+      User2 := AutoMapper.Map(User);
+      //User2 := TUser2.Create;
+      //User.MapTo(User2);
+      //User2.MapFrom(User);
+      //User2 := User.Map<TUser2>;
+      //UserClone := User.Clone as TUser;
+      //User2 := TUser2(User.Clone);
+      //User2 := TMapper<TUserBase>.Clone(User) as TUser2;
+
+      cout('COMPARE USER VS USER2',etTrace);
+      cout('User.Id = %d / User2.IdUser = %d',[User.Id,User2.IdUser],etInfo);
+      cout('User.CreationDate = %s / User2.CreationDate = %s',[DateTimeToStr(User.CreationDate),DateTimetoStr(User2.CreationDate)],etInfo);
+      cout('User.Name = %s / User2.Name = %s',[User.Name,User2.Name],etInfo);
+      cout('User.Age = %d / User2.Age = %d',[User.Age,User2.Age],etInfo);
+      cout('User.Numbers = %d / User2.Numbers = %d',[User.Numbers[1],User2.Numbers[1]],etInfo);
+      cout('User.Cash = %d / User2.Money = %d',[User.Cash,User2.Money],etInfo);
+      cout('User.Job.Name = %s / User2.Job.Name = %s',[User.Job.Name,User2.Job.Name],etInfo);
+      cout('User.Job.DateFrom = %s / User2.Job.DateFrom = %s',[DateTimeToStr(User.Job.DateFrom),DateTimeToStr(User2.Job.DateFrom)],etInfo);
+      cout('User.Car.Model = %s / User2.Car.Model = %s',[User.Car.Model,User2.Car.Model],etInfo);
+
+      cout(' ',etInfo);
+      cout('USER AS JSON RESULT',etTrace);
+      cout('%s',[User.ToJson],etInfo);
+      cout(' ',etInfo);
+      cout('USER2 AS JSON RESULT',etTrace);
+      cout('%s',[User2.ToJson],etInfo);
+
+    finally
+      AutoMapper.Free;
+      User.Free;
+      User2.Free;
+    end;
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.

+ 621 - 0
samples/delphi/QuickAutoMapper/AutoMappingObjects.dproj

@@ -0,0 +1,621 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+    <PropertyGroup>
+        <ProjectGuid>{3F29272C-7851-41C3-B29E-C0ACD8029C21}</ProjectGuid>
+        <ProjectVersion>18.4</ProjectVersion>
+        <FrameworkType>None</FrameworkType>
+        <MainSource>AutoMappingObjects.dpr</MainSource>
+        <Base>True</Base>
+        <Config Condition="'$(Config)'==''">Debug</Config>
+        <Platform Condition="'$(Platform)'==''">Win32</Platform>
+        <TargetedPlatforms>1</TargetedPlatforms>
+        <AppType>Console</AppType>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
+        <Base_Android>true</Base_Android>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
+        <Base_iOSDevice32>true</Base_iOSDevice32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
+        <Base_iOSDevice64>true</Base_iOSDevice64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
+        <Base_iOSSimulator>true</Base_iOSSimulator>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='OSX32' and '$(Base)'=='true') or '$(Base_OSX32)'!=''">
+        <Base_OSX32>true</Base_OSX32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
+        <Base_Win32>true</Base_Win32>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
+        <Base_Win64>true</Base_Win64>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+        <Cfg_1>true</Cfg_1>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
+        <Cfg_1_Win32>true</Cfg_1_Win32>
+        <CfgParent>Cfg_1</CfgParent>
+        <Cfg_1>true</Cfg_1>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+        <Cfg_2>true</Cfg_2>
+        <CfgParent>Base</CfgParent>
+        <Base>true</Base>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base)'!=''">
+        <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
+        <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
+        <DCC_E>false</DCC_E>
+        <DCC_N>false</DCC_N>
+        <DCC_S>false</DCC_S>
+        <DCC_F>false</DCC_F>
+        <DCC_K>false</DCC_K>
+        <DCC_UsePackage>RESTComponents;FireDACIBDriver;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
+        <SanitizedProjectName>AutoMappingObjects</SanitizedProjectName>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Android)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;CoolTrayIcon_D210_XE7;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage)</DCC_UsePackage>
+        <Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
+        <Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
+        <Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
+        <Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
+        <Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
+        <Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
+        <Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
+        <Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
+        <Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
+        <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services-ads-7.0.0.dex.jar;google-play-services-analytics-7.0.0.dex.jar;google-play-services-base-7.0.0.dex.jar;google-play-services-identity-7.0.0.dex.jar;google-play-services-maps-7.0.0.dex.jar;google-play-services-panorama-7.0.0.dex.jar;google-play-services-plus-7.0.0.dex.jar;google-play-services-wallet-7.0.0.dex.jar</EnabledSysJars>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FrameViewer;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;TMSFMXPackPkgDXE11;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;dbexpress;IndyCore;dsnap;bindengine;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_OSX32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;tethering;bindcompfmx;inetdb;FmxTeeUI;fmx;fmxdae;dbexpress;IndyCore;dsnap;bindengine;DBXMySQLDriver;FireDACMySQLDriver;FireDACCommonODBC;bindcompdbx;IndyIPCommon;IndyIPServer;IndySystem;fmxFireDAC;FireDACPgDriver;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;xmlrtl;ibxbindings;fmxobj;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win32)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;UbuntuProgressPackage;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;svnui;JvGlobus;FireDACADSDriver;JvPluginSystem;JvMM;tmsxlsdXE11;vcltouch;JvBands;vcldb;bindcompfmx;svn;Intraweb;JvJans;JvNet;inetdb;JvAppFrm;EssentialsDR;vcwdedXE11;vcwdXE11;FmxTeeUI;JvDotNetCtrls;AbbreviaVCLD;fmx;fmxdae;tmsdXE11;vclib;JvWizards;tmsexdXE11;dbexpress;IndyCore;vclx;JvPageComps;dsnap;JvDB;VCLRESTComponents;JclDeveloperTools;vclie;bindengine;DBXMySQLDriver;JvCmp;FireDACMySQLDriver;JvHMI;FireDACCommonODBC;LockBoxDR;bindcompdbx;IndyIPCommon;JvCustom;advchartdedxe11;vcl;IndyIPServer;GR32_D;JvXPCtrls;PngComponents;IndySystem;advchartdxe11;dsnapcon;FireDACMSAccDriver;fmxFireDAC;vclimg;madBasic_;TeeDB;Jcl;FrameViewer;JvCore;JvCrypt;FireDACPgDriver;ibmonitor;FMXTee;SevenZippro;DbxCommonDriver;JvDlgs;JvRuntimeDesign;ibxpress;Tee;JvManagedThreads;xmlrtl;ibxbindings;fmxobj;vclwinx;JvTimeFramework;rtl;GR32_R;DbxClientDriver;CustomIPTransport;vcldsnap;JvSystem;JvStdCtrls;bindcomp;appanalytics;CoolTrayIcon_D210_XE7;tmswizdXE11;nTrayIcon;IndyIPClient;bindcompvcl;TeeUI;TMSFMXPackPkgDXE11;JvDocking;dbxcds;VclSmp;JvPascalInterpreter;adortl;KernowSoftwareFMX;JclVcl;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;JvControls;JvPrintPreview;Analog_XE7;JclContainers;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
+        <BT_BuildType>Debug</BT_BuildType>
+        <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
+        <VerInfo_Locale>1033</VerInfo_Locale>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Base_Win64)'!=''">
+        <DCC_UsePackage>DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;tethering;FireDACADSDriver;vcltouch;vcldb;bindcompfmx;Intraweb;inetdb;EssentialsDR;vcwdXE11;FmxTeeUI;AbbreviaVCLD;fmx;fmxdae;tmsdXE11;vclib;tmsexdXE11;dbexpress;IndyCore;vclx;dsnap;VCLRESTComponents;vclie;bindengine;DBXMySQLDriver;FireDACMySQLDriver;FireDACCommonODBC;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;IndySystem;advchartdxe11;dsnapcon;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDACPgDriver;ibmonitor;FMXTee;DbxCommonDriver;ibxpress;Tee;xmlrtl;ibxbindings;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
+        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
+        <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
+        <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1)'!=''">
+        <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+        <DCC_DebugDCUs>true</DCC_DebugDCUs>
+        <DCC_Optimize>false</DCC_Optimize>
+        <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+        <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+        <DCC_RemoteDebug>true</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
+        <DCC_RemoteDebug>false</DCC_RemoteDebug>
+    </PropertyGroup>
+    <PropertyGroup Condition="'$(Cfg_2)'!=''">
+        <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+        <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+        <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+        <DCC_DebugInformation>0</DCC_DebugInformation>
+    </PropertyGroup>
+    <ItemGroup>
+        <DelphiCompile Include="$(MainSource)">
+            <MainSource>MainSource</MainSource>
+        </DelphiCompile>
+        <BuildConfiguration Include="Release">
+            <Key>Cfg_2</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Base">
+            <Key>Base</Key>
+        </BuildConfiguration>
+        <BuildConfiguration Include="Debug">
+            <Key>Cfg_1</Key>
+            <CfgParent>Base</CfgParent>
+        </BuildConfiguration>
+    </ItemGroup>
+    <ProjectExtensions>
+        <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+        <Borland.ProjectType>Application</Borland.ProjectType>
+        <BorlandProject>
+            <Delphi.Personality>
+                <Source>
+                    <Source Name="MainSource">AutoMappingObjects.dpr</Source>
+                </Source>
+            </Delphi.Personality>
+            <Deployment Version="3">
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\AutoMappingObjects.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>AutoMappingObjects.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployClass Name="AdditionalDebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidClassesDexFile">
+                    <Platform Name="Android">
+                        <RemoteDir>classes</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidGDBServer">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeArmeabiFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidLibnativeMipsFile">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\mips</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidServiceOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashImageDef">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="AndroidSplashStyles">
+                    <Platform Name="Android">
+                        <RemoteDir>res\values</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_DefaultAppIcon">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon144">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xxhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon36">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-ldpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon48">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-mdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon72">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-hdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_LauncherIcon96">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xhdpi</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage426">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-small</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage470">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-normal</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage640">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-large</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="Android_SplashImage960">
+                    <Platform Name="Android">
+                        <RemoteDir>res\drawable-xlarge</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DebugSymbols">
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyFramework">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.framework</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="DependencyModule">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.dll;.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="DependencyPackage">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                        <Extensions>.dylib</Extensions>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                        <Extensions>.bpl</Extensions>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="File">
+                    <Platform Name="Android">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
+                        <Operation>0</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1024">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch1536">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch2048">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPad_Launch768">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch320">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="iPhone_Launch640x1136">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectAndroidManifest">
+                    <Platform Name="Android">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceDebug">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSDeviceResourceRules">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSEntitlements">
+                    <Platform Name="iOSDevice32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSInfoPList">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectiOSResource">
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXEntitlements">
+                    <Platform Name="OSX32">
+                        <RemoteDir>..\</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXInfoPList">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectOSXResource">
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\Resources</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Required="true" Name="ProjectOutput">
+                    <Platform Name="Android">
+                        <RemoteDir>library\lib\armeabi-v7a</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSDevice64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="iOSSimulator">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Linux64">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="OSX32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win32">
+                        <Operation>0</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="ProjectUWPManifest">
+                    <Platform Name="Win32">
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo150">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <DeployClass Name="UWP_DelphiLogo44">
+                    <Platform Name="Win32">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                    <Platform Name="Win64">
+                        <RemoteDir>Assets</RemoteDir>
+                        <Operation>1</Operation>
+                    </Platform>
+                </DeployClass>
+                <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
+                <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
+                <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
+            </Deployment>
+            <Platforms>
+                <Platform value="Android">False</Platform>
+                <Platform value="iOSDevice32">False</Platform>
+                <Platform value="iOSDevice64">False</Platform>
+                <Platform value="iOSSimulator">False</Platform>
+                <Platform value="OSX32">False</Platform>
+                <Platform value="Win32">True</Platform>
+                <Platform value="Win64">False</Platform>
+            </Platforms>
+        </BorlandProject>
+        <ProjectFileVersion>12</ProjectFileVersion>
+    </ProjectExtensions>
+    <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
+    <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
+    <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
+</Project>

二进制
samples/delphi/QuickAutoMapper/AutoMappingObjects.res


+ 1 - 3
samples/delphi/QuickJsonSerializer/JsonSerializer.dpr

@@ -3,9 +3,7 @@ program JsonSerializer;
 uses
   System.StartUpCopy,
   FMX.Forms,
-  main in 'C:\Users\Kike\Documents\Embarcadero\Studio\Projects\JsonUtilsTest\main.pas' {Form1},
-  jsonit in 'C:\Users\Kike\Documents\Embarcadero\Studio\Projects\JsonUtilsTest\jsonit.pas',
-  Quick.Json.Serializer in 'C:\Users\Kike\Documents\Embarcadero\Studio\Projects\JsonUtilsTest\Quick.Json.Serializer.pas';
+  main in 'main.pas' {Form1};
 
 {$R *.res}
 

+ 1 - 3
samples/delphi/QuickJsonSerializer/JsonSerializer.dproj

@@ -246,11 +246,9 @@
         <DelphiCompile Include="$(MainSource)">
             <MainSource>MainSource</MainSource>
         </DelphiCompile>
-        <DCCReference Include="C:\Users\Kike\Documents\Embarcadero\Studio\Projects\JsonUtilsTest\main.pas">
+        <DCCReference Include="main.pas">
             <Form>Form1</Form>
         </DCCReference>
-        <DCCReference Include="C:\Users\Kike\Documents\Embarcadero\Studio\Projects\JsonUtilsTest\jsonit.pas"/>
-        <DCCReference Include="C:\Users\Kike\Documents\Embarcadero\Studio\Projects\JsonUtilsTest\Quick.Json.Serializer.pas"/>
         <BuildConfiguration Include="Debug">
             <Key>Cfg_2</Key>
             <CfgParent>Base</CfgParent>

+ 39 - 0
samples/delphi/QuickJsonSerializer/main.fmx

@@ -0,0 +1,39 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  Caption = 'Form1'
+  ClientHeight = 552
+  ClientWidth = 1182
+  FormFactor.Width = 320
+  FormFactor.Height = 480
+  FormFactor.Devices = [Desktop]
+  OnCreate = FormCreate
+  OnClose = FormClose
+  DesignerMasterStyle = 0
+  object Memo1: TMemo
+    Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
+    DataDetectorTypes = []
+    Position.X = 8.000000000000000000
+    Position.Y = 8.000000000000000000
+    Size.Width = 1169.000000000000000000
+    Size.Height = 497.000000000000000000
+    Size.PlatformDefault = False
+    TabOrder = 0
+    Viewport.Width = 1165.000000000000000000
+    Viewport.Height = 493.000000000000000000
+  end
+  object btnToJson: TButton
+    Position.X = 544.000000000000000000
+    Position.Y = 520.000000000000000000
+    TabOrder = 2
+    Text = 'ToJson'
+    OnClick = btnToJsonClick
+  end
+  object btnFromJson: TButton
+    Position.X = 656.000000000000000000
+    Position.Y = 520.000000000000000000
+    TabOrder = 1
+    Text = 'FromJson'
+    OnClick = btnFromJsonClick
+  end
+end

+ 269 - 0
samples/delphi/QuickJsonSerializer/main.pas

@@ -0,0 +1,269 @@
+unit main;
+
+interface
+
+uses
+  System.SysUtils,
+  System.Types,
+  System.UITypes,
+  System.Classes,
+  System.Variants,
+  System.Generics.Collections,
+  FMX.Types,
+  FMX.Controls,
+  FMX.Forms,
+  FMX.Graphics,
+  FMX.Dialogs,
+  FMX.Controls.Presentation,
+  FMX.ScrollBox,
+  FMX.Memo,
+  FMX.StdCtrls,
+  Quick.JsonRecord,
+  Quick.Base64,
+  Quick.Json.Serializer;
+
+type
+
+  TID = Int64;
+
+  TContactType = (ctInternal, ctExternal);
+  TMessageState = (msPending, msSent, msNotSent);
+
+  TRecipientArray = array of TID;
+
+  TRecipient = record
+    ID : TID;
+    RType : TContactType;
+    Confirm : TMessageState;
+  end;
+
+  TGenre = (gnMale, gnFemale);
+
+  TGroupType = (gtInternal, gtExternal);
+
+  TDayOfWeek = (wdSunday, wdMonday, wdThuesday, wdWednesday, wdThursday, wdFriday, wdSaturday);
+
+  TUserStatus = (usAtOffice, usAtHome, usOnVacation);
+
+  TDays = set of TDayOfWeek;
+
+const
+  DEF_WORKDAYS : TDays = [wdMonday, wdThuesday, wdWednesday, wdThursday, wdFriday];
+  DEF_WEEKEND : TDays = [wdSaturday, wdSunday];
+
+type
+
+  TDepartment = record
+    Id : TID;
+    Name : string;
+  end;
+
+  TContactIdArray = array of TID;
+
+  TGroup = class
+  private
+    fId : TID;
+    fGType : TGroupType;
+  published
+    property Id : TID read fId write fId;
+    property GType : TGroupType read fGType write fGType;
+  end;
+
+  TOptions = class
+  private
+    fOption1 : Integer;
+    fOption2 : string;
+    fAllowGroups : TGroupType;
+  published
+    property Option1 : Integer read fOption1 write fOption1;
+    property Option2 : string read fOption2 write fOption2;
+    property AllowGroups : TGroupType read fAllowGroups write fAllowGroups;
+  end;
+
+  TConnectionInfo = record
+    IP : string;
+    ConnectionDate : TDateTime;
+  end;
+
+  TConnectionArray = array of TConnectionInfo;
+
+  TGroupList = TObjectList<TGroup>;
+
+  TWorkingTime = class
+  private
+    fName : string;
+    fWorkDays : TDays;
+    fFreeDays : TDays;
+  published
+    property Name : string read fName write fName;
+    property WorkDays : TDays read fWorkDays write fWorkDays;
+    property FreeDays : TDays read fFreeDays write fFreeDays;
+  end;
+
+  TLevelPrivilege = array of TID;
+
+  TUser = class(TJsonRecord)
+  private
+    fId : TID;
+    fName : string;
+    fSurname : string;
+    fAge : Integer;
+    fAddress : string;
+    fOptions : TOptions;
+    fLastConnections : TConnectionArray;
+    fMarried : Boolean;
+    fWorkingTime : TWorkingTime;
+    fGenre : TGenre;
+    fDepartment : TDepartment;
+    fBalance : Double;
+    fHireDate : TDateTime;
+    fLevelPrivilege : TLevelPrivilege;
+    fObservations : string;
+    fStatus : TUserStatus;
+    fGroups : TGroupList;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  published
+    [TCommentProperty('Is user Id')]
+    property Id : TID read fId write fId;
+    property Name : string read fName write fName;
+    property Surname : string read fSurname write fSurname;
+    property Age : Integer read fAge write fAge;
+    [TCommentProperty('gnFemale or gnMale')]
+    property Genre : TGenre read fGenre write fGenre;
+    property Department : TDepartment read fDepartment write fDepartment;
+    property Address : string read fAddress write fAddress;
+    property Balance : Double read fBalance write fBalance;
+    [TCustomNameProperty('IsMarried')]
+    property Married : Boolean read fMarried write fMarried;
+    property WorkingTime : TWorkingTime read fWorkingTime write fWorkingTime;
+    property HireDate : TDateTime read fHireDate write fHireDate;
+    [TCommentProperty('Possible values = usAtOffice, usAtHome or usOnVacation')]
+    property Status : TUserStatus read fStatus write fStatus;
+    property LastConnections : TConnectionArray read fLastConnections write fLastConnections;
+    property Observations : string read fObservations write fObservations;
+    property LevelPrivilege : TLevelPrivilege read fLevelPrivilege write fLevelPrivilege;
+    property Options : TOptions read fOptions write fOptions;
+    property Groups : TGroupList read fGroups write fGroups;
+  end;
+
+  TUserList = TObjectList<TUser>;
+
+
+  TForm1 = class(TForm)
+    Memo1: TMemo;
+    btnToJson: TButton;
+    btnFromJson: TButton;
+    procedure FormCreate(Sender: TObject);
+    procedure btnToJsonClick(Sender: TObject);
+    procedure btnFromJsonClick(Sender: TObject);
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+  private
+    { Private declarations }
+  public
+    { Public declarations }
+  end;
+
+var
+  Form1: TForm1;
+  Serializer : TJsonSerializer;
+  User : TUser;
+  User2 : TUser;
+  UserList : TUserList;
+
+implementation
+
+{$R *.fmx}
+
+procedure TForm1.btnFromJsonClick(Sender: TObject);
+var
+  s : string;
+begin
+  if User2 <> nil then User2.Free;
+  User2 := TUser.Create;
+  User2.FromJson(Memo1.Text);
+  //User2.CreateFromJson(Memo1.Text);
+  Memo1.Lines.Add('User2 as json:');
+  Memo1.Lines.Add(User2.ToJson);
+  Memo1.Lines.Add(Format('Groups.OwnedObjects=%s',[BoolToStr(User2.Groups.OwnsObjects,True)]));
+  Memo1.Lines.Add(Format('Groups.Count=%d',[User2.Groups.Count]));
+  Memo1.Lines.Add(Format('Groups.Capacity=%d',[User2.Groups.Capacity]));
+  ShowMessage(Format('%s %s from %s',[User2.Name,User2.Surname,User2.Address]));
+end;
+
+procedure TForm1.btnToJsonClick(Sender: TObject);
+begin
+  Memo1.Text := User.ToJson;
+end;
+
+procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+  if Assigned(User) then User.Free;
+  if Assigned(User2) then User2.Free;
+  Serializer.Free;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+var
+  lastcon : TConnectionInfo;
+  group : TGroup;
+  department : TDepartment;
+begin
+  serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
+  user := TUser.Create;
+  user.Id := 77;
+  user.Name := 'Joe';
+  user.Surname := 'Smith Valdés';
+  user.Age := 30;
+  user.Married := True;
+  user.Address := 'Sunset st. 2 \b';
+  user.Options.Option1 := 1;
+  user.Options.Option2 := 'good';
+  user.Options.AllowGroups := gtExternal;
+  user.Balance := 99.9;
+  user.HireDate := Now();
+  user.LevelPrivilege := [1,2,3,4];
+  user.WorkingTime.Name:= 'WeekConfig';
+  user.WorkingTime.WorkDays := DEF_WORKDAYS;
+  user.WorkingTime.FreeDays := DEF_WEEKEND;
+  user.Observations := 'Good aptitude';
+  department.Id := 10;
+  department.Name := 'IT';
+  user.Department := department;
+  //user.Status := TUserStatus.usOnVacation;
+  //lastcon.IP := '127.0.0.1';
+  //lastcon.ConnectionDate := Now();
+  //User.LastConnections := [lastcon];
+  //lastcon.IP := '192.0.0.1';
+  //lastcon.ConnectionDate := Now();
+  //User.LastConnections := User.LastConnections + [lastcon];
+  group := TGroup.Create;
+  group.Id := 1;
+  group.GType := gtInternal;
+  user.Groups.Add(group);
+  group := TGroup.Create;
+  group.Id := 2;
+  group.GType := gtExternal;
+  user.Groups.Add(group);
+ end;
+
+
+{ TUser }
+
+constructor TUser.Create;
+begin
+  fOptions := TOptions.Create;
+  fWorkingTime := TWorkingTime.Create;
+  fGroups := TGroupList.Create(True);
+end;
+
+destructor TUser.Destroy;
+begin
+  fOptions.Free;
+  fWorkingTime.Free;
+  fGroups.Free;
+  inherited;
+end;
+
+end.

+ 64 - 0
samples/fpc/AutoMapper/AutoMapperObjects.lpi

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="AutoMapperObjects"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="0"/>
+    </RunParams>
+    <RequiredPackages Count="1">
+      <Item1>
+        <PackageName Value="QuickLib"/>
+      </Item1>
+    </RequiredPackages>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="AutoMapperObjects.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="AutoMapperObjects"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 171 - 0
samples/fpc/AutoMapper/AutoMapperObjects.lpr

@@ -0,0 +1,171 @@
+program AutoMapperObjects;
+
+uses
+  SysUtils,
+  Quick.Commons,
+  Quick.Console,
+  Quick.JSONRecord,
+  Quick.AutoMapper;
+
+type
+
+  TJob = class
+  private
+    fName : string;
+    fDateFrom : TDateTime;
+    fDateTo : TDateTime;
+  published
+    property Name : string read fName write fName;
+    property DateFrom : TDateTime read fDateFrom write fDateFrom;
+    property DateTo : TDateTime read fDateTo write fDateTo;
+  end;
+
+  TCarType = (ctOil, ctDiesel);
+
+  TCar = class
+  private
+    fModel : string;
+    fCarType : TCarType;
+  published
+    property Model : string read fModel write fModel;
+    property CarType : TCarType read fCarType write fCarType;
+  end;
+
+  TArrayOfInteger = array of Integer;
+
+  TUserBase = class(TJsonRecord)
+  private
+    fName : string;
+    fAge : Integer;
+    fCreationDate : TDateTime;
+    fNumbers : TArrayOfInteger;
+  published
+    property Name : string read fName write fName;
+    property Age : Integer read fAge write fAge;
+    property CreationDate : TDateTime read fCreationDate write fCreationDate;
+    property Numbers : TArrayOfInteger read fNumbers write fNumbers;
+  end;
+
+  TUser = class(TUserBase)
+  private
+    fId : Int64;
+    fCash : Integer;
+    fJob : TJob;
+    fCar : TCar;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  published
+    property Id : Int64 read fId write fId;
+    property Cash : Integer read fCash write fCash;
+    property Job : TJob read fJob write fJob;
+    property Car : TCar read fCar write fCar;
+  end;
+
+  TUser2 = class(TUserBase)
+  private
+    fIdUser : Int64;
+    fJob : TJob;
+    fMoney : Integer;
+    fCar : TCar;
+  public
+    constructor Create;
+    destructor Destroy; override;
+  published
+    property IdUser : Int64 read fIdUser write fIdUser;
+    property Money : Integer read fMoney write fMoney;
+    property Job : TJob read fJob write fJob;
+    property Car : TCar read fCar write fCar;
+  end;
+
+var
+  User : TUser;
+  User2 : TUser2;
+  AutoMapper : specialize TAutoMapper<TUser,TUser2>;
+
+{ TUser }
+
+constructor TUser.Create;
+begin
+  fCar := TCar.Create;
+  fJob := TJob.Create;
+end;
+
+destructor TUser.Destroy;
+begin
+  fCar.Free;
+  fJob.Free;
+  inherited;
+end;
+
+{ TUser2 }
+
+constructor TUser2.Create;
+begin
+  fCar := TCar.Create;
+  fJob := TJob.Create;
+end;
+
+destructor TUser2.Destroy;
+begin
+  fCar.Free;
+  fJob.Free;
+  inherited;
+end;
+
+begin
+  try
+    User := TUser.Create;
+    User.Id := 17;
+    User.CreationDate := Now();
+    User.Name := 'John Miller';
+    User.Age := 30;
+    User.Numbers := [1,2,3,4,5];
+    User.Cash := 3500;
+    User.Job.Name := 'Designer';
+    User.Job.DateFrom := IncMonth(Now(),-12);
+    User.Job.DateTo := Now();
+    User.Car.Model := 'Ferrari';
+    User.Car.CarType := ctOil;
+    //User2 := TMapper<TUser2>.Map(User);
+    AutoMapper := specialize TAutoMapper<TUser,TUser2>.Create;
+    try
+      AutoMapper.CustomMapping.AddMap('Cash','Money');
+      AutoMapper.CustomMapping.AddMap('Id','IdUser');
+      User2 := AutoMapper.Map(User);
+      //User2 := TUser2.Create;
+      //User.MapTo(User2);
+      //User2.MapFrom(User);
+      //User2 := User.Map<TUser2>;
+      //User2 := TUser2(User.Clone);
+      //User2 := TMapper<TUserBase>.Clone(User) as TUser2;
+
+      cout('COMPARE USER VS USER2',etTrace);
+      cout('User.Id = %d / User2.IdUser = %d',[User.Id,User2.IdUser],etInfo);
+      cout('User.CreationDate = %s / User2.CreationDate = %s',[DateTimeToStr(User.CreationDate),DateTimetoStr(User2.CreationDate)],etInfo);
+      cout('User.Name = %s / User2.Name = %s',[User.Name,User2.Name],etInfo);
+      cout('User.Age = %d / User2.Age = %d',[User.Age,User2.Age],etInfo);
+      //cout('User.Numbers = %d / User2.Numbers = %d',[User.Numbers[1],User2.Numbers[1]],etInfo);
+      cout('User.Cash = %d / User2.Money = %d',[User.Cash,User2.Money],etInfo);
+      cout('User.Job.Name = %s / User2.Job.Name = %s',[User.Job.Name,User2.Job.Name],etInfo);
+      cout('User.Job.DateFrom = %s / User2.Job.DateFrom = %s',[DateTimeToStr(User.Job.DateFrom),DateTimeToStr(User2.Job.DateFrom)],etInfo);
+      cout('User.Car.Model = %s / User2.Car.Model = %s',[User.Car.Model,User2.Car.Model],etInfo);
+
+      cout(' ',etInfo);
+      cout('USER AS JSON RESULT',etTrace);
+      cout('%s',[User.ToJson],etInfo);
+      cout(' ',etInfo);
+      cout('USER2 AS JSON RESULT',etTrace);
+      cout('%s',[User2.ToJson],etInfo);
+
+    finally
+      AutoMapper.Free;
+      User.Free;
+      User2.Free;
+    end;
+    ConsoleWaitForEnterKey;
+  except
+    on E: Exception do
+      Writeln(E.ClassName, ': ', E.Message);
+  end;
+end.