├── .gitattributes ├── sample ├── FastMM4 │ ├── FastMM4.pas │ ├── FastMM4Messages.pas │ ├── FastMM_OSXUtil.pas │ ├── FastMM4LockFreeStack.pas │ ├── FastMM4DataCollector.pas │ └── FastMM4Options.inc ├── UrlParserSample.res ├── UrlParserSample.dpr ├── Main.pas ├── Main.dfm └── UrlParserSample.dproj ├── boss-lock.json ├── boss.json ├── LICENSE ├── README.md ├── .gitignore └── src └── UrlParser.pas /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /sample/FastMM4/FastMM4.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickolasdeluca/UrlParser/HEAD/sample/FastMM4/FastMM4.pas -------------------------------------------------------------------------------- /sample/UrlParserSample.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickolasdeluca/UrlParser/HEAD/sample/UrlParserSample.res -------------------------------------------------------------------------------- /boss-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "d41d8cd98f00b204e9800998ecf8427e", 3 | "updated": "2021-03-12T13:24:56.8099125-03:00", 4 | "installedModules": {} 5 | } -------------------------------------------------------------------------------- /boss.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UrlParser", 3 | "description": "", 4 | "version": "1.0.0", 5 | "homepage": "", 6 | "mainsrc": "./src", 7 | "projects": [], 8 | "dependencies": {} 9 | } -------------------------------------------------------------------------------- /sample/UrlParserSample.dpr: -------------------------------------------------------------------------------- 1 | program UrlParserSample; 2 | 3 | uses 4 | Vcl.Forms, 5 | Main in 'Main.pas' {FMain}, 6 | UrlParser in '..\src\UrlParser.pas'; 7 | 8 | {$R *.res} 9 | 10 | begin 11 | {$IFDEF DEBUG} 12 | ReportMemoryLeaksOnShutdown := True; 13 | {$ENDIF} 14 | 15 | Application.Initialize; 16 | Application.MainFormOnTaskbar := True; 17 | Application.CreateForm(TFMain, FMain); 18 | Application.Run; 19 | end. 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Nickolas Deluca 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UrlParser for Delphi 2 | 3 | Node.js like URL constructor for Delphi. 4 | 5 | ## How to use it 6 | 7 | Add it to your uses 8 | 9 | ```pascal 10 | uses UrlParser; 11 | ``` 12 | 13 | Then you can simply call it. 14 | 15 | ```pascal 16 | var 17 | url: String; 18 | begin 19 | url := TUrlParser.Create 20 | .Protocol(stHttps) 21 | .Username('myuser') 22 | .Password('mypass') 23 | .BaseUrl('thisisatest.com') 24 | .Port(3574) 25 | .AddResource('tests') 26 | .AddResource('subTests') 27 | .AddParameter('thisisa', 'test') 28 | .AddParameter('useiton', 'delphi') 29 | .ToString); 30 | end; 31 | ``` 32 | 33 | The sample above would return the url below as a string 34 | 35 | ` 36 | https://myuser:mypass@thisisatest.com:3574/tests/subTests?thisisa=test&useiton=delphi 37 | ` 38 | 39 | New parsing method is now availabe. 40 | 41 | ```pascal 42 | var 43 | LUrlObject: IUrlParser; 44 | begin 45 | LUrlObject := TUrlParser.Create.Parse('https://www.thisisatest.com/tests/subTests?thisisa=test&useiton=delphi'); 46 | end; 47 | ``` 48 | 49 | The sample above would return a `IUrlParser` interface that would contain following attributes: `Protocol`, `BaseUrl`, `Resources` and `Parameters` of the parsed url. 50 | 51 | ### How to install it 52 | 53 | #### Install it manually 54 | 55 | Simply drop the UrlParser.pas in your project's folder and add it to the project. 56 | 57 | #### Installation using [**Boss**](https://github.com/HashLoad/boss) 58 | 59 | ```shell 60 | boss install github.com/nickolasdeluca/UrlParser 61 | ``` 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/delphi 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=delphi 3 | 4 | ### Delphi ### 5 | # Uncomment these types if you want even more clean repository. But be careful. 6 | # It can make harm to an existing project source. Read explanations below. 7 | # 8 | # Resource files are binaries containing manifest, project icon and version info. 9 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 10 | #*.res 11 | # Type library file (binary). In old Delphi versions it should be stored. 12 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 13 | #*.tlb 14 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 15 | # Uncomment this if you are not using diagrams or use newer Delphi version. 16 | #*.ddp 17 | # Visual LiveBindings file. Added in Delphi XE2. 18 | # Uncomment this if you are not using LiveBindings Designer. 19 | #*.vlb 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # C++ object files produced when C/C++ Output file generation is configured. 24 | # Uncomment this if you are not using external objects (zlib library for example). 25 | #*.obj 26 | 27 | # Delphi compiler-generated binaries (safe to delete) 28 | *.exe 29 | *.dll 30 | *.bpl 31 | *.bpi 32 | *.dcp 33 | *.so 34 | *.apk 35 | *.drc 36 | *.map 37 | *.dres 38 | *.rsm 39 | *.tds 40 | *.dcu 41 | *.lib 42 | *.a 43 | *.o 44 | *.ocx 45 | 46 | # Delphi autogenerated files (duplicated info) 47 | *.cfg 48 | *.hpp 49 | *Resource.rc 50 | 51 | # Delphi local files (user-specific info) 52 | *.local 53 | *.identcache 54 | *.projdata 55 | *.tvsconfig 56 | *.dsk 57 | 58 | # Delphi history and backups 59 | __history/ 60 | __recovery/ 61 | *.~* 62 | 63 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 64 | *.stat 65 | 66 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss 67 | modules/ 68 | 69 | # End of https://www.toptal.com/developers/gitignore/api/delphi 70 | -------------------------------------------------------------------------------- /sample/Main.pas: -------------------------------------------------------------------------------- 1 | unit Main; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, 7 | System.Variants, System.Classes, System.StrUtils, 8 | Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, 9 | UrlParser, Vcl.ExtCtrls, Vcl.WinXPanels, Vcl.Buttons; 10 | 11 | type 12 | TFMain = class(TForm) 13 | cpSamples: TCardPanel; 14 | cdTestToString: TCard; 15 | btSampler: TButton; 16 | mmUrl: TMemo; 17 | pnControlCards: TPanel; 18 | btNext: TSpeedButton; 19 | btPrevious: TSpeedButton; 20 | cdTestObjectCreation: TCard; 21 | mmParsedInfo: TMemo; 22 | btParse: TButton; 23 | edUrl: TEdit; 24 | procedure btSamplerClick(Sender: TObject); 25 | procedure btNextClick(Sender: TObject); 26 | procedure btPreviousClick(Sender: TObject); 27 | procedure cpSamplesCardChange(Sender: TObject; PrevCard, NextCard: TCard); 28 | procedure btParseClick(Sender: TObject); 29 | private 30 | { Private declarations } 31 | public 32 | { Public declarations } 33 | end; 34 | 35 | var 36 | FMain: TFMain; 37 | 38 | implementation 39 | 40 | uses System.SysUtils; 41 | 42 | {$R *.dfm} 43 | 44 | procedure TFMain.btNextClick(Sender: TObject); 45 | begin 46 | cpSamples.NextCard; 47 | end; 48 | 49 | procedure TFMain.btParseClick(Sender: TObject); 50 | var 51 | LUrlObject: IUrlParser; 52 | LResource, LResources: String; 53 | LParam, LParams: String; 54 | begin 55 | if String(edUrl.Text).IsEmpty then 56 | Exit; 57 | 58 | LUrlObject := TUrlParser.Create.Parse(edUrl.Text); 59 | 60 | mmParsedInfo.Lines.Clear; 61 | 62 | mmParsedInfo.Lines.Add('Unparsed URL: ' + edUrl.Text); 63 | 64 | mmParsedInfo.Lines.Add(''); 65 | 66 | mmParsedInfo.Lines.Add('Protocol: ' + IntToStr(Integer(LUrlObject.Protocol))); 67 | 68 | mmParsedInfo.Lines.Add('Username: ' + LUrlObject.Username); 69 | mmParsedInfo.Lines.Add('Password: ' + LUrlObject.Password); 70 | 71 | mmParsedInfo.Lines.Add('BaseUrl: ' + LUrlObject.BaseUrl); 72 | 73 | mmParsedInfo.Lines.Add('Port: ' + IntToStr(LUrlObject.Port)); 74 | 75 | for LResource in LUrlObject.Resources do 76 | LResources := LResources + IfThen(LResources.IsEmpty, '', ', ') + LResource; 77 | mmParsedInfo.Lines.Add('Resources: ' + LResources); 78 | 79 | for LParam in LUrlObject.Parameters do 80 | LParams := LParams + IfThen(LParams.IsEmpty, '', ', ') + LParam; 81 | mmParsedInfo.Lines.Add('Params: ' + LParams); 82 | 83 | mmParsedInfo.Lines.Add(''); 84 | 85 | mmParsedInfo.Lines.Add('Reconstructed URL: ' + LUrlObject.ToString); 86 | end; 87 | 88 | procedure TFMain.btPreviousClick(Sender: TObject); 89 | begin 90 | cpSamples.PreviousCard; 91 | end; 92 | 93 | procedure TFMain.btSamplerClick(Sender: TObject); 94 | begin 95 | mmUrl.Clear; 96 | 97 | mmUrl.Lines.Add(TUrlParser.Create 98 | .Protocol(stHttps) 99 | .BaseUrl('www.thisisatest.com') 100 | .AddResource('tests') 101 | .AddResource('subTests') 102 | .AddParameter('thisisa', 'test') 103 | .AddParameter('useiton', 'delphi') 104 | .ToString); 105 | end; 106 | 107 | procedure TFMain.cpSamplesCardChange(Sender: TObject; PrevCard, 108 | NextCard: TCard); 109 | begin 110 | pnControlCards.Caption := NextCard.Hint; 111 | end; 112 | 113 | end. 114 | -------------------------------------------------------------------------------- /sample/FastMM4/FastMM4Messages.pas: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Fast Memory Manager: Messages 4 | 5 | English translation by Pierre le Riche. 6 | 7 | } 8 | 9 | unit FastMM4Messages; 10 | 11 | interface 12 | 13 | {$Include FastMM4Options.inc} 14 | 15 | const 16 | {The name of the debug info support DLL} 17 | {$IFDEF MACOS} 18 | FullDebugModeLibraryName32Bit = 'libFastMM_FullDebugMode.dylib'; 19 | {$ELSE} 20 | FullDebugModeLibraryName32Bit = 'FastMM_FullDebugMode.dll'; 21 | {$ENDIF} 22 | FullDebugModeLibraryName64Bit = 'FastMM_FullDebugMode64.dll'; 23 | {Event log strings} 24 | LogFileExtension = '_MemoryManager_EventLog.txt'#0; 25 | CRLF = #13#10; 26 | EventSeparator = '--------------------------------'; 27 | {Class name messages} 28 | UnknownClassNameMsg = 'Unknown'; 29 | {Memory dump message} 30 | MemoryDumpMsg = #13#10#13#10'Current memory dump of 256 bytes starting at pointer address '; 31 | {Block Error Messages} 32 | BlockScanLogHeader = 'Allocated block logged by LogAllocatedBlocksToFile. The size is: '; 33 | ErrorMsgHeader = 'FastMM has detected an error during a '; 34 | GetMemMsg = 'GetMem'; 35 | FreeMemMsg = 'FreeMem'; 36 | ReallocMemMsg = 'ReallocMem'; 37 | BlockCheckMsg = 'free block scan'; 38 | OperationMsg = ' operation. '; 39 | BlockHeaderCorruptedMsg = 'The block header has been corrupted. '; 40 | BlockFooterCorruptedMsg = 'The block footer has been corrupted. '; 41 | FreeModifiedErrorMsg = 'FastMM detected that a block has been modified after being freed. '; 42 | FreeModifiedDetailMsg = #13#10#13#10'Modified byte offsets (and lengths): '; 43 | DoubleFreeErrorMsg = 'An attempt has been made to free/reallocate an unallocated block.'; 44 | WrongMMFreeErrorMsg = 'An attempt has been made to free/reallocate a block that was allocated through a different FastMM instance. Check your memory manager sharing settings.'; 45 | PreviousBlockSizeMsg = #13#10#13#10'The previous block size was: '; 46 | CurrentBlockSizeMsg = #13#10#13#10'The block size is: '; 47 | PreviousObjectClassMsg = #13#10#13#10'The block was previously used for an object of class: '; 48 | CurrentObjectClassMsg = #13#10#13#10'The block is currently used for an object of class: '; 49 | PreviousAllocationGroupMsg = #13#10#13#10'The allocation group was: '; 50 | PreviousAllocationNumberMsg = #13#10#13#10'The allocation number was: '; 51 | CurrentAllocationGroupMsg = #13#10#13#10'The allocation group is: '; 52 | CurrentAllocationNumberMsg = #13#10#13#10'The allocation number is: '; 53 | BlockErrorMsgTitle = 'Memory Error Detected'; 54 | VirtualMethodErrorHeader = 'FastMM has detected an attempt to call a virtual method on a freed object. An access violation will now be raised in order to abort the current operation.'; 55 | InterfaceErrorHeader = 'FastMM has detected an attempt to use an interface of a freed object. An access violation will now be raised in order to abort the current operation.'; 56 | BlockHeaderCorruptedNoHistoryMsg = ' Unfortunately the block header has been corrupted so no history is available.'; 57 | FreedObjectClassMsg = #13#10#13#10'Freed object class: '; 58 | VirtualMethodName = #13#10#13#10'Virtual method: '; 59 | VirtualMethodOffset = 'Offset +'; 60 | VirtualMethodAddress = #13#10#13#10'Virtual method address: '; 61 | {Stack trace messages} 62 | CurrentThreadIDMsg = #13#10#13#10'The current thread ID is 0x'; 63 | CurrentStackTraceMsg = ', and the stack trace (return addresses) leading to this error is:'; 64 | ThreadIDPrevAllocMsg = #13#10#13#10'This block was previously allocated by thread 0x'; 65 | ThreadIDAtAllocMsg = #13#10#13#10'This block was allocated by thread 0x'; 66 | ThreadIDAtFreeMsg = #13#10#13#10'The block was previously freed by thread 0x'; 67 | ThreadIDAtObjectAllocMsg = #13#10#13#10'The object was allocated by thread 0x'; 68 | ThreadIDAtObjectFreeMsg = #13#10#13#10'The object was subsequently freed by thread 0x'; 69 | StackTraceMsg = ', and the stack trace (return addresses) at the time was:'; 70 | {Installation Messages} 71 | AlreadyInstalledMsg = 'FastMM4 is already installed.'; 72 | AlreadyInstalledTitle = 'Already installed.'; 73 | OtherMMInstalledMsg = 'FastMM4 cannot be installed since another third party memory ' 74 | + 'manager has already installed itself.'#13#10'If you want to use FastMM4, ' 75 | + 'please make sure that FastMM4.pas is the very first unit in the "uses"' 76 | + #13#10'section of your project''s .dpr file.'; 77 | OtherMMInstalledTitle = 'Cannot install FastMM4 - Another memory manager is already installed'; 78 | MemoryAllocatedMsg = 'FastMM4 cannot install since memory has already been ' 79 | + 'allocated through the default memory manager.'#13#10'FastMM4.pas MUST ' 80 | + 'be the first unit in your project''s .dpr file, otherwise memory may ' 81 | + 'be allocated'#13#10'through the default memory manager before FastMM4 ' 82 | + 'gains control. '#13#10#13#10'If you are using an exception trapper ' 83 | + 'like MadExcept (or any tool that modifies the unit initialization ' 84 | + 'order),'#13#10'go into its configuration page and ensure that the ' 85 | + 'FastMM4.pas unit is initialized before any other unit.'; 86 | MemoryAllocatedTitle = 'Cannot install FastMM4 - Memory has already been allocated'; 87 | {Leak checking messages} 88 | LeakLogHeader = 'A memory block has been leaked. The size is: '; 89 | LeakMessageHeader = 'This application has leaked memory. '; 90 | SmallLeakDetail = 'The small block leaks are' 91 | {$ifdef HideExpectedLeaksRegisteredByPointer} 92 | + ' (excluding expected leaks registered by pointer)' 93 | {$endif} 94 | + ':'#13#10; 95 | LargeLeakDetail = 'The sizes of leaked medium and large blocks are' 96 | {$ifdef HideExpectedLeaksRegisteredByPointer} 97 | + ' (excluding expected leaks registered by pointer)' 98 | {$endif} 99 | + ': '; 100 | BytesMessage = ' bytes: '; 101 | AnsiStringBlockMessage = 'AnsiString'; 102 | UnicodeStringBlockMessage = 'UnicodeString'; 103 | LeakMessageFooter = #13#10 104 | {$ifndef HideMemoryLeakHintMessage} 105 | + #13#10'Note: ' 106 | {$ifdef RequireIDEPresenceForLeakReporting} 107 | + 'This memory leak check is only performed if Delphi is currently running on the same computer. ' 108 | {$endif} 109 | {$ifdef FullDebugMode} 110 | {$ifdef LogMemoryLeakDetailToFile} 111 | + 'Memory leak detail is logged to a text file in the same folder as this application. ' 112 | {$else} 113 | + 'Enable the "LogMemoryLeakDetailToFile" to obtain a log file containing detail on memory leaks. ' 114 | {$endif} 115 | {$else} 116 | + 'To obtain a log file containing detail on memory leaks, enable the "FullDebugMode" and "LogMemoryLeakDetailToFile" conditional defines. ' 117 | {$endif} 118 | + 'To disable this memory leak check, undefine "EnableMemoryLeakReporting".'#13#10 119 | {$endif} 120 | + #0; 121 | LeakMessageTitle = 'Memory Leak Detected'; 122 | {$ifdef UseOutputDebugString} 123 | FastMMInstallMsg = 'FastMM has been installed.'; 124 | FastMMInstallSharedMsg = 'Sharing an existing instance of FastMM.'; 125 | FastMMUninstallMsg = 'FastMM has been uninstalled.'; 126 | FastMMUninstallSharedMsg = 'Stopped sharing an existing instance of FastMM.'; 127 | {$endif} 128 | {$ifdef DetectMMOperationsAfterUninstall} 129 | InvalidOperationTitle = 'MM Operation after uninstall.'; 130 | InvalidGetMemMsg = 'FastMM has detected a GetMem call after FastMM was uninstalled.'; 131 | InvalidFreeMemMsg = 'FastMM has detected a FreeMem call after FastMM was uninstalled.'; 132 | InvalidReallocMemMsg = 'FastMM has detected a ReallocMem call after FastMM was uninstalled.'; 133 | InvalidAllocMemMsg = 'FastMM has detected an AllocMem call after FastMM was uninstalled.'; 134 | {$endif} 135 | 136 | {$ifdef LogLockContention} 137 | LockingReportTitle = 'Locking Report'; 138 | LockingReportHeader = 'Top locking contention sites'; 139 | {$endif} 140 | 141 | {$ifdef UseReleaseStack} 142 | {$ifdef DebugReleaseStack} 143 | ReleaseStackUsageHeader = 'Release stack usage statistics'; 144 | ReleaseStackUsageSmallBlocksMsg1 = 'Small blocks ['; 145 | ReleaseStackUsageSmallBlocksMsg2 = ']: '; 146 | ReleaseStackUsageTotalSmallBlocksMsg = 'Total small blocks: '; 147 | ReleaseStackUsageMediumBlocksMsg = 'Medium blocks: '; 148 | ReleaseStackUsageLargeBlocksMsg = 'Large blocks: '; 149 | ReleaseStackUsageTotalMemoryMsg = 'Total memory: '; 150 | ReleaseStackUsageBuffers1Msg = ' in '; 151 | ReleaseStackUsageBuffers2Msg = ' buffers ['; 152 | {$endif} 153 | {$endif} 154 | 155 | implementation 156 | 157 | end. 158 | 159 | -------------------------------------------------------------------------------- /sample/Main.dfm: -------------------------------------------------------------------------------- 1 | object FMain: TFMain 2 | Left = 0 3 | Top = 0 4 | Caption = 'UrlParser sample' 5 | ClientHeight = 269 6 | ClientWidth = 494 7 | Color = 4802889 8 | Font.Charset = DEFAULT_CHARSET 9 | Font.Color = clWindowText 10 | Font.Height = -11 11 | Font.Name = 'Segoe UI' 12 | Font.Style = [] 13 | OldCreateOrder = False 14 | Position = poScreenCenter 15 | PixelsPerInch = 96 16 | TextHeight = 13 17 | object cpSamples: TCardPanel 18 | Left = 0 19 | Top = 0 20 | Width = 494 21 | Height = 236 22 | Align = alClient 23 | ActiveCard = cdTestToString 24 | BevelOuter = bvNone 25 | Caption = 'cpSamples' 26 | TabOrder = 0 27 | OnCardChange = cpSamplesCardChange 28 | object cdTestToString: TCard 29 | Left = 0 30 | Top = 0 31 | Width = 494 32 | Height = 236 33 | Hint = 'Simple creation' 34 | Caption = 'cdTestToString' 35 | CardIndex = 0 36 | TabOrder = 0 37 | object btSampler: TButton 38 | AlignWithMargins = True 39 | Left = 5 40 | Top = 211 41 | Width = 484 42 | Height = 25 43 | Margins.Left = 5 44 | Margins.Top = 5 45 | Margins.Right = 5 46 | Margins.Bottom = 0 47 | Align = alBottom 48 | Caption = 'Test it!' 49 | TabOrder = 0 50 | OnClick = btSamplerClick 51 | end 52 | object mmUrl: TMemo 53 | AlignWithMargins = True 54 | Left = 5 55 | Top = 5 56 | Width = 484 57 | Height = 201 58 | Margins.Left = 5 59 | Margins.Top = 5 60 | Margins.Right = 5 61 | Margins.Bottom = 0 62 | Align = alClient 63 | ReadOnly = True 64 | TabOrder = 1 65 | end 66 | end 67 | object cdTestObjectCreation: TCard 68 | Left = 0 69 | Top = 0 70 | Width = 494 71 | Height = 236 72 | Hint = 'Object creation and usage' 73 | Caption = 'cdTestObjectCreation' 74 | CardIndex = 1 75 | TabOrder = 1 76 | ExplicitWidth = 185 77 | ExplicitHeight = 41 78 | object mmParsedInfo: TMemo 79 | AlignWithMargins = True 80 | Left = 5 81 | Top = 31 82 | Width = 484 83 | Height = 175 84 | Margins.Left = 5 85 | Margins.Top = 5 86 | Margins.Right = 5 87 | Margins.Bottom = 0 88 | Align = alClient 89 | ReadOnly = True 90 | TabOrder = 0 91 | ExplicitTop = 56 92 | ExplicitHeight = 150 93 | end 94 | object btParse: TButton 95 | AlignWithMargins = True 96 | Left = 5 97 | Top = 211 98 | Width = 484 99 | Height = 25 100 | Margins.Left = 5 101 | Margins.Top = 5 102 | Margins.Right = 5 103 | Margins.Bottom = 0 104 | Align = alBottom 105 | Caption = 'Parse it!' 106 | TabOrder = 1 107 | OnClick = btParseClick 108 | ExplicitLeft = 10 109 | end 110 | object edUrl: TEdit 111 | AlignWithMargins = True 112 | Left = 5 113 | Top = 5 114 | Width = 484 115 | Height = 21 116 | Margins.Left = 5 117 | Margins.Top = 5 118 | Margins.Right = 5 119 | Margins.Bottom = 0 120 | Align = alTop 121 | TabOrder = 2 122 | TextHint = 'Type your URL here' 123 | ExplicitLeft = 184 124 | ExplicitTop = 112 125 | ExplicitWidth = 121 126 | end 127 | end 128 | end 129 | object pnControlCards: TPanel 130 | AlignWithMargins = True 131 | Left = 0 132 | Top = 236 133 | Width = 494 134 | Height = 33 135 | Margins.Left = 0 136 | Margins.Top = 0 137 | Margins.Right = 0 138 | Margins.Bottom = 0 139 | Align = alBottom 140 | BevelOuter = bvNone 141 | Caption = 'Simple creation' 142 | Font.Charset = DEFAULT_CHARSET 143 | Font.Color = clWhite 144 | Font.Height = -11 145 | Font.Name = 'Segoe UI' 146 | Font.Style = [] 147 | ParentFont = False 148 | TabOrder = 1 149 | object btNext: TSpeedButton 150 | AlignWithMargins = True 151 | Left = 466 152 | Top = 5 153 | Width = 23 154 | Height = 23 155 | Margins.Left = 5 156 | Margins.Top = 5 157 | Margins.Right = 5 158 | Margins.Bottom = 5 159 | Align = alRight 160 | Flat = True 161 | Glyph.Data = { 162 | 36030000424D3603000000000000360000002800000010000000100000000100 163 | 18000000000000030000C30E0000C30E00000000000000000000FF00FFFF00FF 164 | FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 165 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF 166 | 00FFB57A4EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 167 | FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB57A4EC07A5DFF00FFFF00FFFF00 168 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF 169 | 00FFB57A4EEAB085BE7B5CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 170 | FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB57A4EF0B78BEBB286C07B5FFF00 171 | FFFF00FFFF00FFFF00FFFF00FFB57A4EB57A4EB57A4EB57A4EB57A4EB57A4EB5 172 | 7A4EB57A4EF0B78BF0B78BEBB286C07D5EFF00FFFF00FFFF00FFFF00FFB57A4E 173 | F0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BEAB0 174 | 85BE7B5CFF00FFFF00FFFF00FFB57A4EF0B78BF0B78BF0B78BF0B78BF0B78BF0 175 | B78BF0B78BF0B78BF0B78BF0B78BF0B78BEBB287C17E5EFF00FFFF00FFB57A4E 176 | F0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B7 177 | 8BEBB286C07D5EFF00FFFF00FFB57A4EF0B78BF0B78BF0B78BF0B78BF0B78BF0 178 | B78BF0B78BF0B78BF0B78BF0B78BEAB185BE7C5BFF00FFFF00FFFF00FFB57A4E 179 | B57A4EB57A4EB57A4EB57A4EB57A4EB57A4EB57A4EF0B78BF0B78BEAB185BF7C 180 | 5DFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF 181 | 00FFB57A4EF0B78BEBB286C07D5EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 182 | FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB57A4EEBB286C07D5EFF00FFFF00 183 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF 184 | 00FFB57A4EC07D5CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 185 | FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB57A4EFF00FFFF00FFFF00FFFF00 186 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF 187 | 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} 188 | OnClick = btNextClick 189 | ExplicitLeft = 216 190 | ExplicitTop = 8 191 | ExplicitHeight = 22 192 | end 193 | object btPrevious: TSpeedButton 194 | AlignWithMargins = True 195 | Left = 5 196 | Top = 5 197 | Width = 23 198 | Height = 23 199 | Margins.Left = 5 200 | Margins.Top = 5 201 | Margins.Right = 5 202 | Margins.Bottom = 5 203 | Align = alLeft 204 | Flat = True 205 | Glyph.Data = { 206 | 36030000424D3603000000000000360000002800000010000000100000000100 207 | 18000000000000030000C30E0000C30E00000000000000000000FF00FFFF00FF 208 | FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 209 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB5 210 | 7A4EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 211 | FF00FFFF00FFFF00FFFF00FFBF7B5DB57A4EFF00FFFF00FFFF00FFFF00FFFF00 212 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFBE7B5CEAB184B5 213 | 7A4EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 214 | FF00FFFF00FFC07B5FEBB286F0B78BB57A4EFF00FFFF00FFFF00FFFF00FFFF00 215 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC07D5EEBB286F0B78BF0B78BB5 216 | 7A4EB57A4EB57A4EB57A4EB57A4EB57A4EB57A4EB57A4EFF00FFFF00FFFF00FF 217 | BE7B5CEAB085F0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B7 218 | 8BF0B78BB57A4EFF00FFFF00FFC07E5FEBB287F0B78BF0B78BF0B78BF0B78BF0 219 | B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BB57A4EFF00FFFF00FFC07D5E 220 | EBB286F0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B7 221 | 8BF0B78BB57A4EFF00FFFF00FFFF00FFBF7D5CEAB185F0B78BF0B78BF0B78BF0 222 | B78BF0B78BF0B78BF0B78BF0B78BF0B78BF0B78BB57A4EFF00FFFF00FFFF00FF 223 | FF00FFBF7C5DEAB185F0B78BF0B78BB57A4EB57A4EB57A4EB57A4EB57A4EB57A 224 | 4EB57A4EB57A4EFF00FFFF00FFFF00FFFF00FFFF00FFBF7D5DEBB286F0B78BB5 225 | 7A4EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 226 | FF00FFFF00FFFF00FFC07D5EEBB386B57A4EFF00FFFF00FFFF00FFFF00FFFF00 227 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFBF7D5BB5 228 | 7A4EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF 229 | FF00FFFF00FFFF00FFFF00FFFF00FFB57A4EFF00FFFF00FFFF00FFFF00FFFF00 230 | FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF 231 | 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} 232 | OnClick = btPreviousClick 233 | ExplicitLeft = 216 234 | ExplicitTop = 8 235 | ExplicitHeight = 22 236 | end 237 | end 238 | end 239 | -------------------------------------------------------------------------------- /src/UrlParser.pas: -------------------------------------------------------------------------------- 1 | unit UrlParser; 2 | 3 | interface 4 | 5 | Uses 6 | { System } 7 | System.Generics.Collections, System.Classes, 8 | System.SysUtils, System.NetEncoding, System.Math; 9 | 10 | type 11 | TProtocol = (stNone, stHttp, stHttps); 12 | 13 | IUrlParser = interface 14 | ['{992CD585-6821-433A-B1A5-B6E305A50844}'] 15 | function Parse(AURI: String): IUrlParser; 16 | 17 | function Protocol(AProtocol: TProtocol): IUrlParser; overload; 18 | function Protocol: TProtocol; overload; 19 | 20 | function Username(AUsername: String): IUrlParser; overload; 21 | function Username: string; overload; 22 | 23 | function Password(APassword: String): IUrlParser; overload; 24 | function Password: string; overload; 25 | 26 | function BaseUrl(AUrl: String): IUrlParser; overload; 27 | function BaseUrl: String; overload; 28 | 29 | function Port(APort: Integer): IUrlParser; overload; 30 | function Port: Integer; overload; 31 | 32 | function AddResource(AResource: String): IUrlParser; 33 | function Resources: TList; 34 | 35 | function AddParameter(AName: String; AValue: String): IUrlParser; overload; 36 | function AddParameter(APair: String): IUrlParser; overload; 37 | function Parameters: TStringlist; 38 | 39 | function ToString: String; 40 | end; 41 | 42 | TUrlParser = class(TInterfacedObject, IUrlParser) 43 | protected 44 | {$IF CompilerVersion <= 23.0} 45 | FNameValueSeparator: Char; 46 | property NameValueSeparator: Char read FNameValueSeparator write FNameValueSeparator; 47 | {$ENDIF} 48 | private 49 | FProtocol: TProtocol; 50 | FBaseURL: string; 51 | FResources: TList; 52 | FParameters: TStringlist; 53 | FUsername: string; 54 | FPassword: string; 55 | FPort: Integer; 56 | public 57 | function Parse(AURI: String): IUrlParser; 58 | 59 | function Protocol(AProtocol: TProtocol): IUrlParser; overload; 60 | function Protocol: TProtocol; overload; 61 | 62 | function Username(AUsername: String): IUrlParser; overload; 63 | function Username: string; overload; 64 | 65 | function Password(APassword: String): IUrlParser; overload; 66 | function Password: string; overload; 67 | 68 | function BaseUrl(AUrl: String): IUrlParser; overload; 69 | function BaseUrl: String; overload; 70 | 71 | function Port(APort: Integer): IUrlParser; overload; 72 | function Port: Integer; overload; 73 | 74 | function AddResource(AResource: String): IUrlParser; 75 | function Resources: TList; 76 | 77 | function AddParameter(AName: String; AValue: String): IUrlParser; overload; 78 | function AddParameter(APair: String): IUrlParser; overload; 79 | function Parameters: TStringlist; 80 | 81 | function ToString: String; override; 82 | 83 | constructor Create; 84 | destructor Destroy; override; 85 | end; 86 | 87 | implementation 88 | 89 | uses 90 | System.StrUtils; 91 | 92 | type 93 | TProtocolHelper = record Helper for TProtocol 94 | function Parse(const AValue: string): TProtocol; 95 | function ToString: string; 96 | end; 97 | 98 | { TProtocolHelper } 99 | 100 | function TProtocolHelper.Parse(const AValue: string): TProtocol; 101 | var 102 | I: Integer; 103 | begin 104 | Result := TProtocol.stNone; 105 | 106 | for I := Ord(Low(TProtocol)) to Ord(High(TProtocol)) do 107 | begin 108 | if AValue = TProtocol(I).ToString then 109 | begin 110 | Result := TProtocol(I); 111 | Break 112 | end; 113 | end; 114 | 115 | Self := Result; 116 | end; 117 | 118 | function TProtocolHelper.ToString: string; 119 | begin 120 | case Self of 121 | stNone: 122 | Result := ''; 123 | stHttp: 124 | Result := 'http://'; 125 | stHttps: 126 | Result := 'https://'; 127 | else 128 | Result := ''; 129 | end; 130 | end; 131 | 132 | { TUrlParser } 133 | 134 | constructor TUrlParser.Create; 135 | begin 136 | FBaseUrl := ''; 137 | {$IF CompilerVersion <= 23.0} 138 | FNameValueSeparator := '='; 139 | {$ENDIF} 140 | FParameters := TStringlist.Create; 141 | FResources := TList.Create; 142 | end; 143 | 144 | destructor TUrlParser.Destroy; 145 | begin 146 | FResources.Free; 147 | FParameters.Free; 148 | 149 | inherited; 150 | end; 151 | 152 | function TUrlParser.Parameters: TStringlist; 153 | begin 154 | Result := FParameters; 155 | end; 156 | 157 | function TUrlParser.Parse(AURI: String): IUrlParser; 158 | var 159 | LFragment: String; 160 | LURI: String; 161 | LHasProtocol, LHasPaths, LHasParameters, LHasHashes, LHasUserPass, LHasPort: Boolean; 162 | begin 163 | Result := Self; 164 | 165 | LURI := AURI.Trim(['/']); 166 | 167 | if Length(LURI) <= 0 then 168 | Exit; 169 | 170 | LHasProtocol := ContainsStr(LURI, '://'); 171 | LHasPaths := ContainsStr(LURI, '/'); 172 | LHasParameters := ContainsStr(LURI, '?'); 173 | LHasHashes := ContainsStr(LURI, '#'); 174 | LHasUserPass := ((ContainsStr(LURI, '@') and ContainsStr(LURI, ':'))); 175 | 176 | if LHasProtocol then 177 | begin 178 | LFragment := Copy(LURI, 0, Pos('://', LURI) + 2); 179 | 180 | FProtocol.Parse(LFragment); 181 | 182 | Delete(LURI, 1, Length(LFragment)); 183 | end; 184 | 185 | if Length(LURI) <= 0 then 186 | Exit; 187 | 188 | if (LHasUserPass) then 189 | begin 190 | while (Pos('@', LURI) > 0) do 191 | begin 192 | LFragment := Copy(LURI, 0, Pos('@', LURI) - 1); 193 | 194 | if (ContainsStr(LFragment, ':')) then 195 | begin 196 | Result.Username(Copy(LFragment, 0, Pos(':', LFragment) - 1)); 197 | Result.Password(Copy(LFragment, Pos(':', LFragment) + 1, LFragment.Length)); 198 | 199 | Delete(LURI, 1, Length(LFragment) + 1); 200 | end; 201 | end; 202 | end; 203 | 204 | if Length(LURI) <= 0 then 205 | Exit; 206 | 207 | LHasPort := ContainsStr(LURI, ':'); 208 | 209 | LFragment := Copy(LURI, 0, Pos(IfThen(LHasPort, ':', '/'), LURI) - 1); 210 | 211 | FBaseUrl := LFragment; 212 | 213 | Delete(LURI, 1, Length(LFragment) + 1); 214 | 215 | if Length(LURI) <= 0 then 216 | Exit; 217 | 218 | if (LHasPort) then 219 | begin 220 | LFragment := Copy(LURI, 0, Pos('/', LURI) - 1); 221 | 222 | Result.Port(StrToIntDef(LFragment, 0)); 223 | 224 | Delete(LURI, 1, Length(LFragment) + 1); 225 | end; 226 | 227 | if Length(LURI) <= 0 then 228 | Exit; 229 | 230 | if LHasPaths then 231 | begin 232 | while (Pos('/', LURI) > 0) do 233 | begin 234 | LFragment := Copy(LURI, 0, Pos('/', LURI) - 1); 235 | 236 | Result.Resources.Add(LFragment); 237 | 238 | Delete(LURI, 1, Length(LFragment) + 1); 239 | end; 240 | 241 | LFragment := Copy(LURI, 0, IfThen(LHasParameters, 242 | Pos('?', LURI) - 1, 243 | Length(LURI))); 244 | 245 | FResources.Add(LFragment); 246 | 247 | Delete(LURI, 1, Length(LFragment)); 248 | end; 249 | 250 | if Length(LURI) <= 0 then 251 | Exit; 252 | 253 | if LHasParameters then 254 | begin 255 | Delete(LURI, 1, 1); 256 | 257 | while (Pos('&', LURI) > 0) do 258 | begin 259 | LFragment := Copy(LURI, 0, Pos('&', LURI) - 1); 260 | 261 | AddParameter(LFragment); 262 | 263 | Delete(LURI, 1, Length(LFragment) + 1); 264 | end; 265 | 266 | LFragment := Copy(LURI, 0, IfThen(LHasHashes, 267 | Pos('#', LURI) - 1, 268 | Length(LURI))); 269 | 270 | AddParameter(LFragment); 271 | 272 | Delete(LURI, 1, Length(LFragment)); 273 | end; 274 | end; 275 | 276 | function TUrlParser.Username(AUsername: String): IUrlParser; 277 | begin 278 | Result := Self; 279 | FUsername := AUsername; 280 | end; 281 | 282 | function TUrlParser.Username: string; 283 | begin 284 | Result := FUsername; 285 | end; 286 | 287 | function TUrlParser.Password(APassword: String): IUrlParser; 288 | begin 289 | Result := Self; 290 | FPassword := APassword; 291 | end; 292 | 293 | function TUrlParser.Password: string; 294 | begin 295 | Result := FPassword; 296 | end; 297 | 298 | function TUrlParser.Port(APort: Integer): IUrlParser; 299 | begin 300 | Result := Self; 301 | FPort := APort; 302 | end; 303 | 304 | function TUrlParser.Port: Integer; 305 | begin 306 | Result := FPort; 307 | end; 308 | 309 | function TUrlParser.Protocol: TProtocol; 310 | begin 311 | Result := FProtocol; 312 | end; 313 | 314 | function TUrlParser.Protocol(AProtocol: TProtocol): IUrlParser; 315 | begin 316 | Result := Self; 317 | FProtocol := AProtocol; 318 | end; 319 | 320 | function TUrlParser.AddParameter(AName: String; AValue: String): IUrlParser; 321 | begin 322 | Result := Self; 323 | 324 | {$IF CompilerVersion > 23.0} 325 | FParameters.AddPair(AName, AValue); 326 | {$ELSE} 327 | AddParameter(AName + NameValueSeparator + AValue); 328 | {$ENDIF} 329 | end; 330 | 331 | function TUrlParser.AddParameter(APair: String): IUrlParser; 332 | begin 333 | FParameters.Add(APair); 334 | end; 335 | 336 | function TUrlParser.AddResource(AResource: String): IUrlParser; 337 | begin 338 | Result := Self; 339 | Result.Resources.Add(AResource); 340 | end; 341 | 342 | function TUrlParser.BaseUrl: String; 343 | begin 344 | Result := FBaseURL; 345 | end; 346 | 347 | function TUrlParser.BaseUrl(AUrl: String): IUrlParser; 348 | begin 349 | Result := Self; 350 | FBaseUrl := AUrl; 351 | end; 352 | 353 | function TUrlParser.ToString: String; 354 | var 355 | AParam: String; 356 | AResource: String; 357 | begin 358 | Result := Protocol.ToString; 359 | 360 | if (not(Username.IsEmpty)) or (not(Password.IsEmpty)) then 361 | Result := Result + Username + ':' + Password + '@'; 362 | 363 | Result := Result + BaseUrl; 364 | 365 | if (Port > 0) then 366 | Result := Result + ':' + IntToStr(Port); 367 | 368 | for AResource in Resources do 369 | Result := Result + '/' + AResource; 370 | 371 | for AParam in FParameters do 372 | Result := Result + IfThen(Result.Contains('?'), '&', '?') + AParam; 373 | 374 | Result := 375 | {$IF CompilerVersion > 23.0} 376 | TNetEncoding.URL.Encode(Result, [], []); 377 | {$ELSE} 378 | TNetEncoding.URL.Encode(Result); 379 | {$ENDIF} 380 | end; 381 | 382 | function TUrlParser.Resources: TList; 383 | begin 384 | Result := FResources; 385 | end; 386 | 387 | end. 388 | -------------------------------------------------------------------------------- /sample/FastMM4/FastMM_OSXUtil.pas: -------------------------------------------------------------------------------- 1 | unit FastMM_OSXUtil; 2 | 3 | interface 4 | 5 | type 6 | LPCSTR = PAnsiChar; 7 | LPSTR = PAnsiChar; 8 | DWORD = Cardinal; 9 | BOOL = Boolean; 10 | 11 | PSystemTime = ^TSystemTime; 12 | _SYSTEMTIME = record 13 | wYear: Word; 14 | wMonth: Word; 15 | wDayOfWeek: Word; 16 | wDay: Word; 17 | wHour: Word; 18 | wMinute: Word; 19 | wSecond: Word; 20 | wMilliseconds: Word; 21 | end; 22 | TSystemTime = _SYSTEMTIME; 23 | SYSTEMTIME = _SYSTEMTIME; 24 | SIZE_T = NativeUInt; 25 | PUINT_PTR = ^UIntPtr; 26 | 27 | const 28 | PAGE_NOACCESS = 1; 29 | PAGE_READONLY = 2; 30 | PAGE_READWRITE = 4; 31 | PAGE_WRITECOPY = 8; 32 | PAGE_EXECUTE = $10; 33 | PAGE_EXECUTE_READ = $20; 34 | PAGE_EXECUTE_READWRITE = $40; 35 | PAGE_GUARD = $100; 36 | PAGE_NOCACHE = $200; 37 | MEM_COMMIT = $1000; 38 | MEM_RESERVE = $2000; 39 | MEM_DECOMMIT = $4000; 40 | MEM_RELEASE = $8000; 41 | MEM_FREE = $10000; 42 | MEM_PRIVATE = $20000; 43 | MEM_MAPPED = $40000; 44 | MEM_RESET = $80000; 45 | MEM_TOP_DOWN = $100000; 46 | 47 | EXCEPTION_ACCESS_VIOLATION = DWORD($C0000005); 48 | 49 | 50 | //function GetModuleHandleA(lpModuleName: LPCSTR): HMODULE; stdcall; 51 | function GetEnvironmentVariableA(lpName: LPCSTR; lpBuffer: LPSTR; nSize: DWORD): DWORD; stdcall; overload; 52 | function DeleteFileA(lpFileName: LPCSTR): BOOL; stdcall; 53 | function VirtualAlloc(lpvAddress: Pointer; dwSize: SIZE_T; flAllocationType, flProtect: DWORD): Pointer; stdcall; 54 | function VirtualFree(lpAddress: Pointer; dwSize, dwFreeType: Cardinal): LongBool; stdcall; 55 | 56 | procedure RaiseException(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD; 57 | lpArguments: PUINT_PTR); stdcall; 58 | 59 | type 60 | PSecurityAttributes = ^TSecurityAttributes; 61 | _SECURITY_ATTRIBUTES = record 62 | nLength: DWORD; 63 | lpSecurityDescriptor: Pointer; 64 | bInheritHandle: BOOL; 65 | end; 66 | TSecurityAttributes = _SECURITY_ATTRIBUTES; 67 | SECURITY_ATTRIBUTES = _SECURITY_ATTRIBUTES; 68 | 69 | const 70 | GENERIC_READ = DWORD($80000000); 71 | GENERIC_WRITE = $40000000; 72 | OPEN_ALWAYS = 4; 73 | FILE_ATTRIBUTE_NORMAL = $00000080; 74 | FILE_BEGIN = 0; 75 | FILE_CURRENT = 1; 76 | FILE_END = 2; 77 | INVALID_SET_FILE_POINTER = DWORD(-1); 78 | 79 | procedure GetLocalTime(var lpSystemTime: TSystemTime); stdcall; 80 | 81 | function CreateFileA(lpFileName: LPCSTR; dwDesiredAccess, dwShareMode: DWORD; 82 | lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD; 83 | hTemplateFile: THandle): THandle; stdcall; 84 | 85 | function SetFilePointer(hFile: THandle; lDistanceToMove: Longint; 86 | lpDistanceToMoveHigh: PLongInt; dwMoveMethod: DWORD): DWORD; stdcall; 87 | 88 | function CloseHandle(hObject: THandle): BOOL; stdcall; 89 | 90 | implementation 91 | 92 | uses 93 | Posix.Stdlib, Posix.Unistd, Posix.SysMman, Posix.Fcntl, Posix.SysStat, Posix.SysTime, Posix.Time, Posix.Errno, Posix.Signal; 94 | 95 | function CreateFileA(lpFileName: LPCSTR; dwDesiredAccess, dwShareMode: DWORD; 96 | lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD; 97 | hTemplateFile: THandle): THandle; stdcall; 98 | var 99 | Flags: Integer; 100 | FileAccessRights: Integer; 101 | begin 102 | // O_RDONLY open for reading only 103 | // O_WRONLY open for writing only 104 | // O_RDWR open for reading and writing 105 | // O_NONBLOCK do not block on open or for data to become available 106 | // O_APPEND append on each write 107 | // O_CREAT create file if it does not exist 108 | // O_TRUNC truncate size to 0 109 | // O_EXCL error if O_CREAT and the file exists 110 | // O_SHLOCK atomically obtain a shared lock 111 | // O_EXLOCK atomically obtain an exclusive lock 112 | // O_NOFOLLOW do not follow symlinks 113 | // O_SYMLINK allow open of symlinks 114 | // O_EVTONLY descriptor requested for event notifications only 115 | // O_CLOEXEC mark as close-on-exec 116 | 117 | Flags := 0; 118 | FileAccessRights := S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH or S_IWOTH; 119 | 120 | case dwDesiredAccess and (GENERIC_READ or GENERIC_WRITE) of //= (GENERIC_READ or GENERIC_WRITE) then 121 | GENERIC_READ or GENERIC_WRITE: Flags := Flags or O_RDWR; 122 | GENERIC_READ: Flags := Flags or O_RDONLY; 123 | GENERIC_WRITE: Flags := Flags or O_WRONLY; 124 | else 125 | Exit(THandle(-1)); 126 | end; 127 | 128 | case dwCreationDisposition of 129 | // CREATE_NEW: 130 | // CREATE_ALWAYS: 131 | // OPEN_EXISTING: 132 | OPEN_ALWAYS: Flags := Flags or O_CREAT; 133 | // TRUNCATE_EXISTING: 134 | end; 135 | 136 | Result := THandle(__open(lpFileName, Flags, FileAccessRights)); 137 | 138 | // ShareMode 139 | 140 | // smode := Mode and $F0 shr 4; 141 | // if ShareMode[smode] <> 0 then 142 | // begin 143 | // LockVar.l_whence := SEEK_SET; 144 | // LockVar.l_start := 0; 145 | // LockVar.l_len := 0; 146 | // LockVar.l_type := ShareMode[smode]; 147 | // Tvar := fcntl(FileHandle, F_SETLK, LockVar); 148 | // Code := errno; 149 | // if (Tvar = -1) and (Code <> EINVAL) and (Code <> ENOTSUP) then 150 | // EINVAL/ENOTSUP - file doesn't support locking 151 | // begin 152 | // __close(FileHandle); 153 | // Exit; 154 | // end; 155 | end; 156 | 157 | type 158 | _LARGE_INTEGER = record 159 | case Integer of 160 | 0: ( 161 | LowPart: DWORD; 162 | HighPart: Longint); 163 | 1: ( 164 | QuadPart: Int64); 165 | end; 166 | 167 | 168 | function SetFilePointer(hFile: THandle; lDistanceToMove: Longint; 169 | lpDistanceToMoveHigh: PLongInt; dwMoveMethod: DWORD): DWORD; stdcall; 170 | var 171 | dist: _LARGE_INTEGER; 172 | begin 173 | dist.LowPart := lDistanceToMove; 174 | if Assigned(lpDistanceToMoveHigh) then 175 | dist.HighPart := lpDistanceToMoveHigh^ 176 | else 177 | dist.HighPart := 0; 178 | 179 | dist.QuadPart := lseek(hFile, dist.QuadPart, dwMoveMethod); // dwMoveMethod = same as in windows 180 | if dist.QuadPart = -1 then 181 | Result := DWORD(-1) 182 | else 183 | begin 184 | Result := dist.LowPart; 185 | if Assigned(lpDistanceToMoveHigh) then 186 | lpDistanceToMoveHigh^ := dist.HighPart; 187 | end; 188 | end; 189 | 190 | procedure GetLocalTime(var lpSystemTime: TSystemTime); stdcall; 191 | var 192 | T: time_t; 193 | TV: timeval; 194 | UT: tm; 195 | begin 196 | gettimeofday(TV, nil); 197 | T := TV.tv_sec; 198 | localtime_r(T, UT); 199 | 200 | lpSystemTime.wYear := UT.tm_year; 201 | lpSystemTime.wMonth := UT.tm_mon; 202 | lpSystemTime.wDayOfWeek := UT.tm_wday; 203 | lpSystemTime.wDay := UT.tm_mday; 204 | lpSystemTime.wHour := UT.tm_hour; 205 | lpSystemTime.wMinute := UT.tm_min; 206 | lpSystemTime.wSecond := UT.tm_sec; 207 | lpSystemTime.wMilliseconds := 0; 208 | end; 209 | 210 | function CloseHandle(hObject: THandle): BOOL; stdcall; 211 | begin 212 | Result := __close(hObject) = 0; 213 | end; 214 | 215 | function StrLen(const Str: PAnsiChar): Cardinal; 216 | begin 217 | Result := Length(Str); 218 | end; 219 | 220 | function StrLCopy(Dest: PAnsiChar; const Source: PAnsiChar; MaxLen: Cardinal): PAnsiChar; 221 | var 222 | Len: Cardinal; 223 | begin 224 | Result := Dest; 225 | Len := StrLen(Source); 226 | if Len > MaxLen then 227 | Len := MaxLen; 228 | Move(Source^, Dest^, Len * SizeOf(AnsiChar)); 229 | Dest[Len] := #0; 230 | end; 231 | 232 | function StrPLCopy(Dest: PAnsiChar; const Source: AnsiString; MaxLen: Cardinal): PAnsiChar; 233 | begin 234 | Result := StrLCopy(Dest, PAnsiChar(Source), MaxLen); 235 | end; 236 | 237 | function GetModuleHandle(lpModuleName: PWideChar): HMODULE; 238 | begin 239 | Result := 0; 240 | if lpModuleName = 'kernel32' then 241 | Result := 1; 242 | end; 243 | 244 | function GetModuleHandleA(lpModuleName: LPCSTR): HMODULE; stdcall; 245 | begin 246 | Result := GetModuleHandle(PChar(string(lpModuleName))); 247 | end; 248 | 249 | function GetEnvironmentVariableA(lpName: LPCSTR; lpBuffer: LPSTR; nSize: DWORD): DWORD; stdcall; overload; 250 | var 251 | Len: Integer; 252 | Env: string; 253 | begin 254 | env := string(getenv(lpName)); 255 | 256 | Len := Length(env); 257 | Result := Len; 258 | if nSize < Result then 259 | Result := nSize; 260 | 261 | StrPLCopy(lpBuffer, env, Result); 262 | if Len > nSize then 263 | SetLastError(122) //ERROR_INSUFFICIENT_BUFFER) 264 | else 265 | SetLastError(0); 266 | end; 267 | 268 | function DeleteFileA(lpFileName: LPCSTR): BOOL; stdcall; 269 | begin 270 | Result := unlink(lpFileName) <> -1; 271 | end; 272 | 273 | // ReservedBlock := VirtualAlloc(Pointer(DebugReservedAddress), 65536, MEM_RESERVE, PAGE_NOACCESS); 274 | 275 | 276 | function VirtualAlloc(lpvAddress: Pointer; dwSize: SIZE_T; flAllocationType, flProtect: DWORD): Pointer; stdcall; 277 | var 278 | PageSize: LongInt; 279 | AllocSize: LongInt; 280 | Protect: Integer; 281 | begin 282 | if lpvAddress <> nil then 283 | begin 284 | if flAllocationType <> MEM_RESERVE then 285 | Exit(0); 286 | 287 | if flProtect <> PAGE_NOACCESS then 288 | Exit(0); 289 | 290 | PageSize := sysconf(_SC_PAGESIZE); 291 | AllocSize := dwSize - (dwSize mod PageSize) + PageSize; 292 | 293 | Result := mmap(lpvAddress, AllocSize, PROT_NONE, MAP_PRIVATE or MAP_ANON, -1, 0); 294 | Exit; 295 | end; 296 | 297 | Result := malloc(dwSize); 298 | FillChar(Result^, dwSize, 0); 299 | //Result := valloc(dwSize); 300 | 301 | 302 | 303 | // FreeItem.Addr := mmap(nil, PageSize, PROT_WRITE or PROT_EXEC, 304 | // MAP_PRIVATE or MAP_ANON, -1, 0); 305 | end; 306 | 307 | function VirtualFree(lpAddress: Pointer; dwSize, dwFreeType: Cardinal): LongBool; stdcall; 308 | begin 309 | Result := True; 310 | if dwFreetype = MEM_RELEASE then 311 | begin 312 | if lpAddress = Pointer($80800000) then 313 | munmap(lpAddress, dwSize) 314 | else 315 | free(lpAddress); 316 | end; 317 | end; 318 | 319 | procedure RaiseException(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD; 320 | lpArguments: PUINT_PTR); stdcall; 321 | begin 322 | WriteLN('ACCESS VIOLATION (set breakpoint in FastMM_OSXUtil: RaiseException for easier debugging)'); 323 | kill(getppid, SIGSEGV); 324 | asm int 3; end; 325 | end; 326 | 327 | 328 | end. 329 | -------------------------------------------------------------------------------- /sample/FastMM4/FastMM4LockFreeStack.pas: -------------------------------------------------------------------------------- 1 | // Based on TOmniBaseBoundedStack class from the OmniThreadLibrary, 2 | // originally written by GJ and Primoz Gabrijelcic. 3 | 4 | unit FastMM4LockFreeStack; 5 | 6 | interface 7 | 8 | type 9 | PReferencedPtr = ^TReferencedPtr; 10 | TReferencedPtr = record 11 | PData : pointer; 12 | Reference: NativeInt; 13 | end; 14 | 15 | PLinkedData = ^TLinkedData; 16 | TLinkedData = packed record 17 | Next: PLinkedData; 18 | Data: record end; //user data, variable size 19 | end; 20 | 21 | TLFStack = record 22 | strict private 23 | FDataBuffer : pointer; 24 | FElementSize : integer; 25 | FNumElements : integer; 26 | FPublicChainP : PReferencedPtr; 27 | FRecycleChainP: PReferencedPtr; 28 | class var 29 | class var obsIsInitialized: boolean; //default is false 30 | class var obsTaskPopLoops : NativeInt; 31 | class var obsTaskPushLoops: NativeInt; 32 | class function PopLink(var chain: TReferencedPtr): PLinkedData; static; 33 | class procedure PushLink(const link: PLinkedData; var chain: TReferencedPtr); static; 34 | procedure MeasureExecutionTimes; 35 | public 36 | procedure Empty; 37 | procedure Initialize(numElements, elementSize: integer); 38 | procedure Finalize; 39 | function IsEmpty: boolean; inline; 40 | function IsFull: boolean; inline; 41 | function Pop(var value): boolean; 42 | function Push(const value): boolean; 43 | property ElementSize: integer read FElementSize; 44 | property NumElements: integer read FNumElements; 45 | end; 46 | 47 | implementation 48 | 49 | uses 50 | Windows; 51 | 52 | {$IF CompilerVersion < 23} 53 | {$IFNDEF CPUX64} 54 | type 55 | NativeInt = integer; 56 | NativeUInt = cardinal; 57 | {$ENDIF} 58 | {$IFEND} 59 | 60 | var 61 | CASAlignment: integer; //required alignment for the CAS function - 8 or 16, depending on the platform 62 | 63 | function RoundUpTo(value: pointer; granularity: integer): pointer; 64 | begin 65 | Result := pointer((((NativeInt(value) - 1) div granularity) + 1) * granularity); 66 | end; 67 | 68 | function GetCPUTimeStamp: int64; 69 | asm 70 | rdtsc 71 | {$IFDEF CPUX64} 72 | shl rdx, 32 73 | or rax, rdx 74 | {$ENDIF CPUX64} 75 | end; 76 | 77 | function GetThreadId: NativeInt; 78 | //result := GetCurrentThreadId; 79 | asm 80 | {$IFNDEF CPUX64} 81 | mov eax, fs:[$18] //eax := thread information block 82 | mov eax, [eax + $24] //eax := thread id 83 | {$ELSE CPUX64} 84 | mov rax, gs:[abs $30] 85 | mov eax, [rax + $48] 86 | {$ENDIF CPUX64} 87 | end; 88 | 89 | function CAS(const oldValue, newValue: NativeInt; var destination): boolean; overload; 90 | asm 91 | {$IFDEF CPUX64} 92 | mov rax, oldValue 93 | {$ENDIF CPUX64} 94 | lock cmpxchg [destination], newValue 95 | setz al 96 | end; 97 | 98 | function CAS(const oldValue, newValue: pointer; var destination): boolean; overload; 99 | asm 100 | {$IFDEF CPUX64} 101 | mov rax, oldValue 102 | {$ENDIF CPUX64} 103 | lock cmpxchg [destination], newValue 104 | setz al 105 | end; 106 | 107 | function CAS(const oldData: pointer; oldReference: NativeInt; newData: pointer; 108 | newReference: NativeInt; var destination): boolean; overload; 109 | asm 110 | {$IFNDEF CPUX64} 111 | push edi 112 | push ebx 113 | mov ebx, newData 114 | mov ecx, newReference 115 | mov edi, destination 116 | lock cmpxchg8b qword ptr [edi] 117 | pop ebx 118 | pop edi 119 | {$ELSE CPUX64} 120 | .noframe 121 | push rbx //rsp := rsp - 8 ! 122 | mov rax, oldData 123 | mov rbx, newData 124 | mov rcx, newReference 125 | mov r8, [destination + 8] //+8 with respect to .noframe 126 | lock cmpxchg16b [r8] 127 | pop rbx 128 | {$ENDIF CPUX64} 129 | setz al 130 | end; 131 | 132 | { TLFStack } 133 | 134 | procedure TLFStack.Empty; 135 | var 136 | linkedData: PLinkedData; 137 | begin 138 | repeat 139 | linkedData := PopLink(FPublicChainP^); 140 | if not assigned(linkedData) then 141 | break; //repeat 142 | PushLink(linkedData, FRecycleChainP^); 143 | until false; 144 | end; 145 | 146 | procedure TLFStack.Finalize; 147 | begin 148 | HeapFree(GetProcessHeap, 0, FDataBuffer); 149 | end; 150 | 151 | procedure TLFStack.Initialize(numElements, elementSize: integer); 152 | var 153 | bufferElementSize : integer; 154 | currElement : PLinkedData; 155 | dataBuffer : pointer; 156 | iElement : integer; 157 | nextElement : PLinkedData; 158 | roundedElementSize: integer; 159 | begin 160 | Assert(SizeOf(NativeInt) = SizeOf(pointer)); 161 | Assert(numElements > 0); 162 | Assert(elementSize > 0); 163 | FNumElements := numElements; 164 | FElementSize := elementSize; 165 | //calculate element size, round up to next aligned value 166 | roundedElementSize := (elementSize + SizeOf(pointer) - 1) AND NOT (SizeOf(pointer) - 1); 167 | //calculate buffer element size, round up to next aligned value 168 | bufferElementSize := ((SizeOf(TLinkedData) + roundedElementSize) + SizeOf(pointer) - 1) AND NOT (SizeOf(pointer) - 1); 169 | //calculate DataBuffer 170 | FDataBuffer := HeapAlloc(GetProcessHeap, HEAP_GENERATE_EXCEPTIONS, bufferElementSize * numElements + 2 * SizeOf(TReferencedPtr) + CASAlignment); 171 | dataBuffer := RoundUpTo(FDataBuffer, CASAlignment); 172 | if NativeInt(dataBuffer) AND (SizeOf(pointer) - 1) <> 0 then 173 | // TODO 1 raise exception - how? 174 | Halt; //raise Exception.Create('TOmniBaseContainer: obcBuffer is not aligned'); 175 | FPublicChainP := dataBuffer; 176 | inc(NativeInt(dataBuffer), SizeOf(TReferencedPtr)); 177 | FRecycleChainP := dataBuffer; 178 | inc(NativeInt(dataBuffer), SizeOf(TReferencedPtr)); 179 | //Format buffer to recycleChain, init obsRecycleChain and obsPublicChain. 180 | //At the beginning, all elements are linked into the recycle chain. 181 | FRecycleChainP^.PData := dataBuffer; 182 | currElement := FRecycleChainP^.PData; 183 | for iElement := 0 to FNumElements - 2 do begin 184 | nextElement := PLinkedData(NativeInt(currElement) + bufferElementSize); 185 | currElement.Next := nextElement; 186 | currElement := nextElement; 187 | end; 188 | currElement.Next := nil; // terminate the chain 189 | FPublicChainP^.PData := nil; 190 | MeasureExecutionTimes; 191 | end; 192 | 193 | function TLFStack.IsEmpty: boolean; 194 | begin 195 | Result := not assigned(FPublicChainP^.PData); 196 | end; 197 | 198 | function TLFStack.IsFull: boolean; 199 | begin 200 | Result := not assigned(FRecycleChainP^.PData); 201 | end; 202 | 203 | procedure TLFStack.MeasureExecutionTimes; 204 | const 205 | NumOfSamples = 10; 206 | var 207 | TimeTestField: array [0..1] of array [1..NumOfSamples] of int64; 208 | 209 | function GetMinAndClear(routine, count: cardinal): int64; 210 | var 211 | m: cardinal; 212 | n: integer; 213 | x: integer; 214 | begin 215 | Result := 0; 216 | for m := 1 to count do begin 217 | x:= 1; 218 | for n:= 2 to NumOfSamples do 219 | if TimeTestField[routine, n] < TimeTestField[routine, x] then 220 | x := n; 221 | Inc(Result, TimeTestField[routine, x]); 222 | TimeTestField[routine, x] := MaxLongInt; 223 | end; 224 | end; 225 | 226 | var 227 | oldAffinity: NativeUInt; 228 | currElement: PLinkedData; 229 | n : integer; 230 | 231 | begin 232 | if not obsIsInitialized then begin 233 | oldAffinity := SetThreadAffinityMask(GetCurrentThread, 1); 234 | try 235 | //Calculate TaskPopDelay and TaskPushDelay counter values depend on CPU speed!!!} 236 | obsTaskPopLoops := 1; 237 | obsTaskPushLoops := 1; 238 | for n := 1 to NumOfSamples do begin 239 | SwitchToThread; 240 | //Measure RemoveLink rutine delay 241 | TimeTestField[0, n] := GetCPUTimeStamp; 242 | currElement := PopLink(FRecycleChainP^); 243 | TimeTestField[0, n] := GetCPUTimeStamp - TimeTestField[0, n]; 244 | //Measure InsertLink rutine delay 245 | TimeTestField[1, n] := GetCPUTimeStamp; 246 | PushLink(currElement, FRecycleChainP^); 247 | TimeTestField[1, n] := GetCPUTimeStamp - TimeTestField[1, n]; 248 | end; 249 | //Calculate first 4 minimum average for RemoveLink rutine 250 | obsTaskPopLoops := GetMinAndClear(0, 4) div 4; 251 | //Calculate first 4 minimum average for InsertLink rutine 252 | obsTaskPushLoops := GetMinAndClear(1, 4) div 4; 253 | 254 | //This gives better performance (determined experimentally) 255 | obsTaskPopLoops := obsTaskPopLoops * 2; 256 | obsTaskPushLoops := obsTaskPushLoops * 2; 257 | 258 | obsIsInitialized := true; 259 | finally SetThreadAffinityMask(GetCurrentThread, oldAffinity); end; 260 | end; 261 | end; 262 | 263 | function TLFStack.Pop(var value): boolean; 264 | var 265 | linkedData: PLinkedData; 266 | begin 267 | linkedData := PopLink(FPublicChainP^); 268 | Result := assigned(linkedData); 269 | if not Result then 270 | Exit; 271 | Move(linkedData.Data, value, ElementSize); 272 | PushLink(linkedData, FRecycleChainP^); 273 | end; 274 | 275 | class function TLFStack.PopLink(var chain: TReferencedPtr): PLinkedData; 276 | //nil << Link.Next << Link.Next << ... << Link.Next 277 | // ^------ < chainHead 278 | var 279 | AtStartReference: NativeInt; 280 | CurrentReference: NativeInt; 281 | TaskCounter : NativeInt; 282 | ThreadReference : NativeInt; 283 | label 284 | TryAgain; 285 | begin 286 | ThreadReference := GetThreadId + 1; //Reference.bit0 := 1 287 | with chain do begin 288 | TryAgain: 289 | TaskCounter := obsTaskPopLoops; 290 | AtStartReference := Reference OR 1; //Reference.bit0 := 1 291 | repeat 292 | CurrentReference := Reference; 293 | Dec(TaskCounter); 294 | until (TaskCounter = 0) or (CurrentReference AND 1 = 0); 295 | if (CurrentReference AND 1 <> 0) and (AtStartReference <> CurrentReference) or 296 | not CAS(CurrentReference, ThreadReference, Reference) 297 | then 298 | goto TryAgain; 299 | //Reference is set... 300 | Result := PData; 301 | //Empty test 302 | if result = nil then 303 | CAS(ThreadReference, 0, Reference) //Clear Reference if task own reference 304 | else if not CAS(Result, ThreadReference, Result.Next, 0, chain) then 305 | goto TryAgain; 306 | end; //with chain 307 | end; 308 | 309 | function TLFStack.Push(const value): boolean; 310 | var 311 | linkedData: PLinkedData; 312 | begin 313 | linkedData := PopLink(FRecycleChainP^); 314 | Result := assigned(linkedData); 315 | if not Result then 316 | Exit; 317 | Move(value, linkedData.Data, ElementSize); 318 | PushLink(linkedData, FPublicChainP^); 319 | end; 320 | 321 | class procedure TLFStack.PushLink(const link: PLinkedData; var chain: TReferencedPtr); 322 | var 323 | PMemData : pointer; 324 | TaskCounter: NativeInt; 325 | begin 326 | with chain do begin 327 | for TaskCounter := 0 to obsTaskPushLoops do 328 | if (Reference AND 1 = 0) then 329 | break; 330 | repeat 331 | PMemData := PData; 332 | link.Next := PMemData; 333 | until CAS(PMemData, link, PData); 334 | end; 335 | end; 336 | 337 | procedure InitializeTimingInfo; 338 | var 339 | stack: TLFStack; 340 | begin 341 | stack.Initialize(10, 4); // enough for initialization 342 | stack.Finalize; 343 | end; 344 | 345 | initialization 346 | {$IFDEF CPUX64} 347 | CASAlignment := 16; 348 | {$ELSE} 349 | CASAlignment := 8; 350 | {$ENDIF CPUX64} 351 | InitializeTimingInfo; 352 | end. 353 | -------------------------------------------------------------------------------- /sample/FastMM4/FastMM4DataCollector.pas: -------------------------------------------------------------------------------- 1 | unit FastMM4DataCollector; 2 | 3 | {$I FastMM4Options.inc} 4 | 5 | interface 6 | 7 | type 8 | TStaticCollector = record 9 | strict private const 10 | CDefaultPromoteGen1_sec = 1; // promote every second 11 | CDefaultPromoteGen1Count = 1; // promote allocations with Count > 1 12 | CGeneration1Size = 1024; 13 | CGeneration2Size = 256; 14 | CCollectedDataSize = CGeneration2Size; 15 | CMaxPointers = 11; // same as in FastMM4 16 | public type 17 | TPointers = record 18 | Pointers: array [1..CMaxPointers] of pointer; 19 | Count : integer; 20 | class operator Equal(const a, b: TPointers): boolean; 21 | end; 22 | TDataInfo = record 23 | Data : TPointers; 24 | Count: integer; 25 | end; 26 | TCollectedData = array [1..CCollectedDataSize] of TDataInfo; 27 | TGenerationOverflowCount = record 28 | Generation1: integer; 29 | Generation2: integer; 30 | end; 31 | strict private type 32 | PDataInfo = ^TDataInfo; 33 | TGenerationPlaceholder = array [1..1] of TDataInfo; 34 | PGenerationPlaceholder = ^TGenerationPlaceholder; 35 | TGenerationInfo = record 36 | Data : PGenerationPlaceholder; 37 | Size : integer; 38 | Last : integer; 39 | NextGeneration : integer; 40 | PromoteEvery_sec: integer; 41 | PromoteCountOver: integer; 42 | OverflowCount : integer; 43 | LastCheck_ms : int64; 44 | end; 45 | var 46 | FGeneration1 : array [1..CGeneration1Size] of TDataInfo; 47 | FGeneration2 : array [1..CGeneration2Size] of TDataInfo; 48 | FGenerationInfo: array [0..2] of TGenerationInfo; //gen0 is used for merging 49 | FLocked : boolean; 50 | FPadding : array [1..3] of byte; 51 | function GetGen1_PromoteCountOver: integer; 52 | function GetGen1_PromoteEvery_sec: integer; 53 | function GetOverflowCount: TGenerationOverflowCount; 54 | procedure Lock; 55 | function Now_ms: int64; inline; 56 | procedure SetGen1_PromoteCountOver(const value: integer); 57 | procedure SetGen1_PromoteEvery_sec(const value: integer); 58 | private 59 | procedure AddToGeneration(generation: integer; const aData: TPointers; 60 | count: integer = 1); 61 | procedure CheckPromoteGeneration(generation: integer); inline; 62 | function FindInGeneration(generation: integer; const aData: TPointers): integer; inline; 63 | function FindInsertionPoint(generation, count: integer): integer; inline; 64 | procedure FlushAllGenerations; 65 | function InsertIntoGeneration(generation: integer; const dataInfo: TDataInfo): boolean; 66 | procedure PromoteGeneration(oldGen, newGen: integer); 67 | procedure ResortGeneration(generation, idxData: integer); 68 | public 69 | procedure Initialize; 70 | procedure Add(const pointers: pointer; count: integer); 71 | procedure GetData(var data: TCollectedData; var count: integer); 72 | procedure Merge(var mergedData: TCollectedData; var mergedCount: integer; 73 | const newData: TCollectedData; newCount: integer); 74 | property Gen1_PromoteCountOver: integer read GetGen1_PromoteCountOver 75 | write SetGen1_PromoteCountOver; 76 | property OverflowCount: TGenerationOverflowCount read GetOverflowCount; 77 | property Gen1_PromoteEvery_sec: integer read GetGen1_PromoteEvery_sec write 78 | SetGen1_PromoteEvery_sec; 79 | end; 80 | PStaticCollector = ^TStaticCollector; 81 | 82 | implementation 83 | 84 | uses 85 | Winapi.Windows; //used in Now_ms 86 | 87 | {$RANGECHECKS OFF} 88 | 89 | // Copied from FastMM4.pas 90 | function LockCmpxchg(CompareVal, NewVal: Byte; AAddress: PByte): Byte; 91 | asm 92 | {$if SizeOf(Pointer) = 4} 93 | {On entry: 94 | al = CompareVal, 95 | dl = NewVal, 96 | ecx = AAddress} 97 | {$ifndef LINUX} 98 | lock cmpxchg [ecx], dl 99 | {$else} 100 | {Workaround for Kylix compiler bug} 101 | db $F0, $0F, $B0, $11 102 | {$endif} 103 | {$else} 104 | {On entry: 105 | cl = CompareVal 106 | dl = NewVal 107 | r8 = AAddress} 108 | .noframe 109 | mov rax, rcx 110 | lock cmpxchg [r8], dl 111 | {$ifend} 112 | end; 113 | 114 | { TStaticCollector.TPointers } 115 | 116 | class operator TStaticCollector.TPointers.Equal(const a, b: TPointers): boolean; 117 | var 118 | i: integer; 119 | begin 120 | Result := a.Count = b.Count; 121 | if Result then 122 | for i := 1 to a.Count do 123 | if a.Pointers[i] <> b.Pointers[i] then 124 | Exit(false); 125 | end; 126 | 127 | { TStaticCollector } 128 | 129 | procedure TStaticCollector.Add(const pointers: pointer; count: integer); 130 | var 131 | ptrData: TPointers; 132 | begin 133 | Lock; 134 | ptrData.Count := CMaxPointers; 135 | if count < CMaxPointers then 136 | ptrData.Count := count; 137 | Move(pointers^, ptrData.Pointers[1], ptrData.Count * SizeOf(pointer)); 138 | AddToGeneration(1, ptrData); 139 | FLocked := false; 140 | end; 141 | 142 | procedure TStaticCollector.AddToGeneration(generation: integer; const aData: TPointers; 143 | count: integer = 1); 144 | var 145 | dataInfo: TDataInfo; 146 | idxData : integer; 147 | begin 148 | CheckPromoteGeneration(generation); 149 | 150 | with FGenerationInfo[generation] do begin 151 | idxData := FindInGeneration(generation, aData); 152 | if idxData >= 1 then begin 153 | Data^[idxData].Count := Data^[idxData].Count + count; 154 | ResortGeneration(generation, idxData); 155 | end 156 | else begin 157 | dataInfo.Data := aData; 158 | dataInfo.Count := count; 159 | InsertIntoGeneration(generation, dataInfo); 160 | end; 161 | end; 162 | end; { TStaticCollector.AddToGeneration } 163 | 164 | procedure TStaticCollector.CheckPromoteGeneration(generation: integer); 165 | begin 166 | with FGenerationInfo[generation] do begin 167 | if NextGeneration > 0 then begin 168 | if LastCheck_ms = 0 then 169 | LastCheck_ms := Now_ms 170 | else if ((Now_ms - LastCheck_ms) div 1000) >= PromoteEvery_sec then begin 171 | PromoteGeneration(generation, NextGeneration); 172 | LastCheck_ms := Now_ms; 173 | end; 174 | end; 175 | end; 176 | end; 177 | 178 | function TStaticCollector.FindInGeneration(generation: integer; const aData: TPointers): 179 | integer; 180 | begin 181 | with FGenerationInfo[generation] do begin 182 | for Result := 1 to Last do 183 | if Data^[Result].Data = aData then 184 | Exit; 185 | end; 186 | Result := 0; 187 | end; 188 | 189 | function TStaticCollector.FindInsertionPoint(generation, count: integer): integer; 190 | var 191 | insert: integer; 192 | begin 193 | with FGenerationInfo[generation] do begin 194 | for insert := Last downto 1 do begin 195 | if Data^[insert].Count > count then 196 | Exit(insert+1); 197 | end; 198 | Result := 1; 199 | end; 200 | end; 201 | 202 | procedure TStaticCollector.FlushAllGenerations; 203 | var 204 | generation: integer; 205 | nextGen : integer; 206 | begin 207 | generation := 1; 208 | while generation <> 0 do begin 209 | nextGen := FGenerationInfo[generation].NextGeneration; 210 | if nextGen > 0 then 211 | PromoteGeneration(generation, nextGen); 212 | generation := nextGen; 213 | end; 214 | end; 215 | 216 | procedure TStaticCollector.GetData(var data: TCollectedData; var count: integer); 217 | begin 218 | Lock; 219 | FlushAllGenerations; 220 | Assert(Length(data) = Length(FGeneration2)); 221 | count := FGenerationInfo[2].Last; 222 | Move(FGeneration2[1], data[1], count * SizeOf(data[1])); 223 | FLocked := false; 224 | end; 225 | 226 | function TStaticCollector.GetGen1_PromoteCountOver: integer; 227 | begin 228 | Result := FGenerationInfo[1].PromoteCountOver; 229 | end; 230 | 231 | function TStaticCollector.GetGen1_PromoteEvery_sec: integer; 232 | begin 233 | Result := FGenerationInfo[1].PromoteEvery_sec; 234 | end; 235 | 236 | function TStaticCollector.GetOverflowCount: TGenerationOverflowCount; 237 | begin 238 | Result.Generation1 := FGenerationInfo[1].OverflowCount; 239 | Result.Generation2 := FGenerationInfo[2].OverflowCount; 240 | end; 241 | 242 | procedure TStaticCollector.Initialize; 243 | begin 244 | Assert(SizeOf(TStaticCollector) mod SizeOf(pointer) = 0); 245 | with FGenerationInfo[1] do begin 246 | Data := @FGeneration1; 247 | Size := CGeneration1Size; 248 | Last := 0; 249 | NextGeneration := 2; 250 | PromoteEvery_sec := CDefaultPromoteGen1_sec; 251 | PromoteCountOver := CDefaultPromoteGen1Count; 252 | LastCheck_ms := 0; 253 | end; 254 | with FGenerationInfo[2] do begin 255 | Data := @FGeneration2; 256 | Size := CGeneration2Size; 257 | NextGeneration := 0; 258 | end; 259 | end; 260 | 261 | function TStaticCollector.InsertIntoGeneration(generation: integer; const dataInfo: 262 | TDataInfo): boolean; 263 | var 264 | idx: integer; 265 | begin 266 | // We already know that this element does not exist in the generation. 267 | 268 | Result := true; 269 | with FGenerationInfo[generation] do begin 270 | idx := FindInsertionPoint(generation, dataInfo.Count); 271 | if idx > Last then begin 272 | if Last = Size then begin 273 | Inc(OverflowCount); 274 | Result := false; 275 | end 276 | else begin 277 | Inc(Last); 278 | Data^[Last] := dataInfo; 279 | end; 280 | end 281 | else begin 282 | if Last < Size then begin 283 | Move(Data^[idx], Data^[idx+1], (Last-idx+1) * SizeOf(Data^[idx])); 284 | Inc(Last); 285 | end 286 | else begin 287 | if Last > idx then 288 | Move(Data^[idx], Data^[idx+1], (Last-idx) * SizeOf(Data^[idx])); 289 | Inc(OverflowCount); 290 | end; 291 | Data^[idx] := dataInfo; 292 | end; 293 | end; 294 | end; 295 | 296 | procedure TStaticCollector.Lock; 297 | begin 298 | {$ifndef AssumeMultiThreaded} 299 | if IsMultiThread then 300 | {$endif} 301 | begin 302 | while LockCmpxchg(0, 1, @FLocked) <> 0 do 303 | begin 304 | {$ifdef NeverSleepOnThreadContention} 305 | {$ifdef UseSwitchToThread} 306 | SwitchToThread; 307 | {$endif} 308 | {$else} 309 | Sleep(0); 310 | if LockCmpxchg(0, 1, @FLocked) = 0 then 311 | Break; 312 | Sleep(1); 313 | {$endif} 314 | end; 315 | end; 316 | end; 317 | 318 | procedure TStaticCollector.Merge(var mergedData: TCollectedData; 319 | var mergedCount: integer; const newData: TCollectedData; newCount: integer); 320 | var 321 | iNew: integer; 322 | begin 323 | // Merges two sorted arrays. 324 | 325 | FGenerationInfo[0].Data := @mergedData; 326 | FGenerationInfo[0].Last := mergedCount; 327 | FGenerationInfo[0].Size := CCollectedDataSize; 328 | FGenerationInfo[0].NextGeneration := 0; 329 | 330 | for iNew := 1 to newCount do 331 | AddToGeneration(0, newData[iNew].Data, newData[iNew].Count); 332 | 333 | mergedCount := FGenerationInfo[0].Last; 334 | end; 335 | 336 | function TStaticCollector.Now_ms: int64; 337 | var 338 | st: TSystemTime; 339 | begin 340 | // We cannot use SysUtils as that gets memory allocator called before FastMM is initialized. 341 | GetSystemTime(st); 342 | SystemTimeToFileTime(st, TFileTime(Result)); 343 | Result := Result div 10000; 344 | end; 345 | 346 | procedure TStaticCollector.PromoteGeneration(oldGen, newGen: integer); 347 | var 348 | canInsert : boolean; 349 | idxNew : integer; 350 | idxOld : integer; 351 | newGenData: PGenerationPlaceholder; 352 | pOldData : PDataInfo; 353 | begin 354 | canInsert := true; 355 | newGenData := FGenerationInfo[newGen].Data; 356 | with FGenerationInfo[oldGen] do begin 357 | for idxOld := 1 to Last do begin 358 | pOldData := @Data^[idxOld]; 359 | if pOldData^.Count <= PromoteCountOver then 360 | break; //for idxOld 361 | idxNew := FindInGeneration(newGen, pOldData^.Data); 362 | if idxNew > 0 then begin 363 | newGenData^[idxNew].Count := newGenData^[idxNew].Count + pOldData^.Count; 364 | ResortGeneration(newGen, idxNew); 365 | end 366 | else if canInsert then 367 | canInsert := InsertIntoGeneration(newGen, pOldData^) 368 | else with FGenerationInfo[newGen] do 369 | Inc(OverflowCount); 370 | end; //for idxOld 371 | Last := 0; 372 | end; 373 | end; 374 | 375 | procedure TStaticCollector.ResortGeneration(generation, idxData: integer); 376 | var 377 | dataInfo: TDataInfo; 378 | idx : integer; 379 | begin 380 | // Data^[idxData].Count was just updated, resort the generation. 381 | with FGenerationInfo[generation] do begin 382 | idx := FindInsertionPoint(generation, Data^[idxData].Count); 383 | if idx < idxData then begin 384 | dataInfo := Data^[idxData]; 385 | Move(Data^[idx], Data^[idx+1], (idxData-idx) * SizeOf(Data^[idx])); 386 | Data^[idx] := dataInfo; 387 | end; 388 | end; 389 | end; 390 | 391 | procedure TStaticCollector.SetGen1_PromoteCountOver(const value: integer); 392 | begin 393 | FGenerationInfo[1].PromoteCountOver := value; 394 | end; 395 | 396 | procedure TStaticCollector.SetGen1_PromoteEvery_sec(const value: integer); 397 | begin 398 | FGenerationInfo[1].PromoteEvery_sec := value; 399 | end; 400 | 401 | end. 402 | -------------------------------------------------------------------------------- /sample/FastMM4/FastMM4Options.inc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Fast Memory Manager: Options Include File 4 | 5 | Set the default options for FastMM here. 6 | 7 | } 8 | 9 | {---------------------------Miscellaneous Options-----------------------------} 10 | 11 | {Enable this define to align all blocks on 16 byte boundaries so aligned SSE 12 | instructions can be used safely. If this option is disabled then some of the 13 | smallest block sizes will be 8-byte aligned instead which may result in a 14 | reduction in memory usage. Medium and large blocks are always 16-byte aligned 15 | irrespective of this setting.} 16 | {.$define Align16Bytes} 17 | 18 | {Enable to use faster fixed-size move routines when upsizing small blocks. 19 | These routines are much faster than the Borland RTL move procedure since they 20 | are optimized to move a fixed number of bytes. This option may be used 21 | together with the FastMove library for even better performance.} 22 | {$define UseCustomFixedSizeMoveRoutines} 23 | 24 | {Enable this option to use an optimized procedure for moving a memory block of 25 | an arbitrary size. Disable this option when using the Fastcode move 26 | ("FastMove") library. Using the Fastcode move library allows your whole 27 | application to gain from faster move routines, not just the memory manager. It 28 | is thus recommended that you use the Fastcode move library in conjunction with 29 | this memory manager and disable this option.} 30 | {$define UseCustomVariableSizeMoveRoutines} 31 | 32 | {Enable this option to only install FastMM as the memory manager when the 33 | application is running inside the Delphi IDE. This is useful when you want 34 | to deploy the same EXE that you use for testing, but only want the debugging 35 | features active on development machines. When this option is enabled and 36 | the application is not being run inside the IDE debugger, then the default 37 | Delphi memory manager will be used (which, since Delphi 2006, is FastMM 38 | without FullDebugMode.} 39 | {.$define InstallOnlyIfRunningInIDE} 40 | 41 | {Due to QC#14070 ("Delphi IDE attempts to free memory after the shutdown code 42 | of borlndmm.dll has been called"), FastMM cannot be uninstalled safely when 43 | used inside a replacement borlndmm.dll for the IDE. Setting this option will 44 | circumvent this problem by never uninstalling the memory manager.} 45 | {.$define NeverUninstall} 46 | 47 | {Set this option when you use runtime packages in this application or library. 48 | This will automatically set the "AssumeMultiThreaded" option. Note that you 49 | have to ensure that FastMM is finalized after all live pointers have been 50 | freed - failure to do so will result in a large leak report followed by a lot 51 | of A/Vs. (See the FAQ for more detail.) You may have to combine this option 52 | with the NeverUninstall option.} 53 | {.$define UseRuntimePackages} 54 | 55 | {-----------------------Concurrency Management Options------------------------} 56 | 57 | {Enable to always assume that the application is multithreaded. Enabling this 58 | option will cause a significant performance hit with single threaded 59 | applications. Enable if you are using multi-threaded third party tools that do 60 | not properly set the IsMultiThread variable. Also set this option if you are 61 | going to share this memory manager between a single threaded application and a 62 | multi-threaded DLL.} 63 | {.$define AssumeMultiThreaded} 64 | 65 | {Enable this option to not call Sleep when a thread contention occurs. This 66 | option will improve performance if the ratio of the number of active threads 67 | to the number of CPU cores is low (typically < 2). With this option set a 68 | thread will usually enter a "busy waiting" loop instead of relinquishing its 69 | timeslice when a thread contention occurs, unless UseSwitchToThread is 70 | also defined (see below) in which case it will call SwitchToThread instead of 71 | Sleep.} 72 | {.$define NeverSleepOnThreadContention} 73 | 74 | {Set this option to call SwitchToThread instead of sitting in a "busy waiting" 75 | loop when a thread contention occurs. This is used in conjunction with the 76 | NeverSleepOnThreadContention option, and has no effect unless 77 | NeverSleepOnThreadContention is also defined. This option may improve 78 | performance with many CPU cores and/or threads of different priorities. Note 79 | that the SwitchToThread API call is only available on Windows 2000 and later.} 80 | {.$define UseSwitchToThread} 81 | 82 | {-----------------------------Debugging Options-------------------------------} 83 | 84 | {Enable this option to suppress the generation of debug info for the 85 | FastMM4.pas unit. This will prevent the integrated debugger from stepping into 86 | the memory manager code.} 87 | {.$define NoDebugInfo} 88 | 89 | {Enable this option to suppress the display of all message dialogs. This is 90 | useful in service applications that should not be interrupted.} 91 | {.$define NoMessageBoxes} 92 | 93 | {Set this option to use the Windows API OutputDebugString procedure to output 94 | debug strings on startup/shutdown and when errors occur.} 95 | {.$define UseOutputDebugString} 96 | 97 | {Set this option to use the assembly language version which is faster than the 98 | pascal version. Disable only for debugging purposes. Setting the 99 | CheckHeapForCorruption option automatically disables this option.} 100 | {$define ASMVersion} 101 | 102 | {FastMM always catches attempts to free the same memory block twice, however it 103 | can also check for corruption of the memory heap (typically due to the user 104 | program overwriting the bounds of allocated memory). These checks are 105 | expensive, and this option should thus only be used for debugging purposes. 106 | If this option is set then the ASMVersion option is automatically disabled.} 107 | {.$define CheckHeapForCorruption} 108 | 109 | {Enable this option to catch attempts to perform MM operations after FastMM has 110 | been uninstalled. With this option set when FastMM is uninstalled it will not 111 | install the previous MM, but instead a dummy MM handler that throws an error 112 | if any MM operation is attempted. This will catch attempts to use the MM 113 | after FastMM has been uninstalled.} 114 | {$define DetectMMOperationsAfterUninstall} 115 | 116 | {Set the following option to do extensive checking of all memory blocks. All 117 | blocks are padded with both a header and trailer that are used to verify the 118 | integrity of the heap. Freed blocks are also cleared to to ensure that they 119 | cannot be reused after being freed. This option slows down memory operations 120 | dramatically and should only be used to debug an application that is 121 | overwriting memory or reusing freed pointers. Setting this option 122 | automatically enables CheckHeapForCorruption and disables ASMVersion. 123 | Very important: If you enable this option your application will require the 124 | FastMM_FullDebugMode.dll library. If this library is not available you will 125 | get an error on startup.} 126 | {.$define FullDebugMode} 127 | 128 | {Set this option to perform "raw" stack traces, i.e. check all entries on the 129 | stack for valid return addresses. Note that this is significantly slower 130 | than using the stack frame tracing method, but is usually more complete. Has 131 | no effect unless FullDebugMode is enabled} 132 | {$define RawStackTraces} 133 | 134 | {Set this option to check for user code that uses an interface of a freed 135 | object. Note that this will disable the checking of blocks modified after 136 | being freed (the two are not compatible). This option has no effect if 137 | FullDebugMode is not also enabled.} 138 | {.$define CatchUseOfFreedInterfaces} 139 | 140 | {Set this option to log all errors to a text file in the same folder as the 141 | application. Memory errors (with the FullDebugMode option set) will be 142 | appended to the log file. Has no effect if "FullDebugMode" is not set.} 143 | {$define LogErrorsToFile} 144 | 145 | {Set this option to log all memory leaks to a text file in the same folder as 146 | the application. Memory leak reports (with the FullDebugMode option set) 147 | will be appended to the log file. Has no effect if "LogErrorsToFile" and 148 | "FullDebugMode" are not also set. Note that usually all leaks are always 149 | logged, even if they are "expected" leaks registered through 150 | AddExpectedMemoryLeaks. Expected leaks registered by pointer may be excluded 151 | through the HideExpectedLeaksRegisteredByPointer option.} 152 | {$define LogMemoryLeakDetailToFile} 153 | 154 | {Deletes the error log file on startup. No effect if LogErrorsToFile is not 155 | also set.} 156 | {.$define ClearLogFileOnStartup} 157 | 158 | {Loads the FASTMM_FullDebugMode.dll dynamically. If the DLL cannot be found 159 | then stack traces will not be available. Note that this may cause problems 160 | due to a changed DLL unload order when sharing the memory manager. Use with 161 | care.} 162 | {.$define LoadDebugDLLDynamically} 163 | 164 | {.$define DoNotInstallIfDLLMissing} 165 | {If the FastMM_FullDebugMode.dll file is not available then FastMM will not 166 | install itself. No effect unless FullDebugMode and LoadDebugDLLDynamically 167 | are also defined.} 168 | 169 | {FastMM usually allocates large blocks from the topmost available address and 170 | medium and small blocks from the lowest available address (This reduces 171 | fragmentation somewhat). With this option set all blocks are always 172 | allocated from the highest available address. If the process has a >2GB 173 | address space and contains bad pointer arithmetic code, this option should 174 | help to catch those errors sooner.} 175 | {$define AlwaysAllocateTopDown} 176 | 177 | {Disables the logging of memory dumps together with the other detail for 178 | memory errors.} 179 | {.$define DisableLoggingOfMemoryDumps} 180 | 181 | {If FastMM encounters a problem with a memory block inside the FullDebugMode 182 | FreeMem handler then an "invalid pointer operation" exception will usually 183 | be raised. If the FreeMem occurs while another exception is being handled 184 | (perhaps in the try.. finally code) then the original exception will be 185 | lost. With this option set FastMM will ignore errors inside FreeMem when an 186 | exception is being handled, thus allowing the original exception to 187 | propagate.} 188 | {$define SuppressFreeMemErrorsInsideException} 189 | 190 | {Adds support for notification of memory manager events in FullDebugMode. 191 | With this define set, the application may assign the OnDebugGetMemFinish, 192 | OnDebugFreeMemStart, etc. callbacks in order to be notified when the 193 | particular memory manager event occurs.} 194 | {.$define FullDebugModeCallBacks} 195 | 196 | {---------------------------Memory Leak Reporting-----------------------------} 197 | 198 | {Set this option to enable reporting of memory leaks. Combine it with the two 199 | options below for further fine-tuning.} 200 | {$define EnableMemoryLeakReporting} 201 | 202 | {Set this option to suppress the display and logging of expected memory leaks 203 | that were registered by pointer. Leaks registered by size or class are often 204 | ambiguous, so these expected leaks are always logged to file (in 205 | FullDebugMode with the LogMemoryLeakDetailToFile option set) and are never 206 | hidden from the leak display if there are more leaks than are expected.} 207 | {$define HideExpectedLeaksRegisteredByPointer} 208 | 209 | {Set this option to require the presence of the Delphi IDE to report memory 210 | leaks. This option has no effect if the option "EnableMemoryLeakReporting" 211 | is not also set.} 212 | {.$define RequireIDEPresenceForLeakReporting} 213 | 214 | {Set this option to require the program to be run inside the IDE debugger to 215 | report memory leaks. This option has no effect if the option 216 | "EnableMemoryLeakReporting" is not also set. Note that this option does not 217 | work with libraries, only EXE projects.} 218 | {$define RequireDebuggerPresenceForLeakReporting} 219 | 220 | {Set this option to require the presence of debug info ($D+ option) in the 221 | compiled unit to perform memory leak checking. This option has no effect if 222 | the option "EnableMemoryLeakReporting" is not also set.} 223 | {.$define RequireDebugInfoForLeakReporting} 224 | 225 | {Set this option to enable manual control of the memory leak report. When 226 | this option is set the ReportMemoryLeaksOnShutdown variable (default = false) 227 | may be changed to select whether leak reporting should be done or not. When 228 | this option is selected then both the variable must be set to true and the 229 | other leak checking options must be applicable for the leak checking to be 230 | done.} 231 | {.$define ManualLeakReportingControl} 232 | 233 | {Set this option to disable the display of the hint below the memory leak 234 | message.} 235 | {.$define HideMemoryLeakHintMessage} 236 | 237 | {--------------------------Instruction Set Options----------------------------} 238 | 239 | {Set this option to enable the use of MMX instructions. Disabling this option 240 | will result in a slight performance hit, but will enable compatibility with 241 | AMD K5, Pentium I and earlier CPUs. MMX is currently only used in the variable 242 | size move routines, so if UseCustomVariableSizeMoveRoutines is not set then 243 | this option has no effect.} 244 | {.$define EnableMMX} 245 | 246 | {Set this option to force the use of MMX instructions without checking 247 | whether the CPU supports it. If this option is disabled then the CPU will be 248 | checked for compatibility first, and if MMX is not supported it will fall 249 | back to the FPU move code. Has no effect unless EnableMMX is also set.} 250 | {$define ForceMMX} 251 | 252 | {-----------------------Memory Manager Sharing Options------------------------} 253 | 254 | {Allow sharing of the memory manager between a main application and DLLs that 255 | were also compiled with FastMM. This allows you to pass dynamic arrays and 256 | long strings to DLL functions provided both are compiled to use FastMM. 257 | Sharing will only work if the library that is supposed to share the memory 258 | manager was compiled with the "AttemptToUseSharedMM" option set. Note that if 259 | the main application is single threaded and the DLL is multi-threaded that you 260 | have to set the IsMultiThread variable in the main application to true or it 261 | will crash when a thread contention occurs. Note that statically linked DLL 262 | files are initialized before the main application, so the main application may 263 | well end up sharing a statically loaded DLL's memory manager and not the other 264 | way around. } 265 | {.$define ShareMM} 266 | 267 | {Allow sharing of the memory manager by a DLL with other DLLs (or the main 268 | application if this is a statically loaded DLL) that were also compiled with 269 | FastMM. Set this option with care in dynamically loaded DLLs, because if the 270 | DLL that is sharing its MM is unloaded and any other DLL is still sharing 271 | the MM then the application will crash. This setting is only relevant for 272 | DLL libraries and requires ShareMM to also be set to have any effect. 273 | Sharing will only work if the library that is supposed to share the memory 274 | manager was compiled with the "AttemptToUseSharedMM" option set. Note that 275 | if DLLs are statically linked then they will be initialized before the main 276 | application and then the DLL will in fact share its MM with the main 277 | application. This option has no effect unless ShareMM is also set.} 278 | {.$define ShareMMIfLibrary} 279 | 280 | {Define this to attempt to share the MM of the main application or other loaded 281 | DLLs in the same process that were compiled with ShareMM set. When sharing a 282 | memory manager, memory leaks caused by the sharer will not be freed 283 | automatically. Take into account that statically linked DLLs are initialized 284 | before the main application, so set the sharing options accordingly.} 285 | {.$define AttemptToUseSharedMM} 286 | 287 | {Define this to enable backward compatibility for the memory manager sharing 288 | mechanism used by Delphi 2006 and 2007, as well as older FastMM versions.} 289 | {$define EnableBackwardCompatibleMMSharing} 290 | 291 | {-----------------------Security Options------------------------} 292 | 293 | {Windows clears physical memory before reusing it in another process. However, 294 | it is not known how quickly this clearing is performed, so it is conceivable 295 | that confidential data may linger in physical memory longer than absolutely 296 | necessary. If you're paranoid about this kind of thing, enable this option to 297 | clear all freed memory before returning it to the operating system. Note that 298 | this incurs a noticeable performance hit.} 299 | {.$define ClearMemoryBeforeReturningToOS} 300 | 301 | {With this option enabled freed memory will immediately be cleared inside the 302 | FreeMem routine. This incurs a big performance hit, but may be worthwhile for 303 | additional peace of mind when working with highly sensitive data. This option 304 | supersedes the ClearMemoryBeforeReturningToOS option.} 305 | {.$define AlwaysClearFreedMemory} 306 | 307 | {----------------------------Lock Contention Logging--------------------------} 308 | 309 | {Define this to lock stack traces for all occasions where GetMem/FreeMem 310 | go to sleep because of lock contention (IOW, when memory manager is already 311 | locked by another thread). At the end of the program execution top 10 sites 312 | (locations with highest occurrence) will be logged to the _MemoryManager_EventLog.txt 313 | file. 314 | This options works with FullDebugMode or without it, but requires 315 | FastMM_FullDebugMode.dll to be present in both cases. 316 | } 317 | {.$define LogLockContention} 318 | 319 | {--------------------------------Option Grouping------------------------------} 320 | 321 | {Enabling this option enables FullDebugMode, InstallOnlyIfRunningInIDE and 322 | LoadDebugDLLDynamically. Consequently, FastMM will install itself in 323 | FullDebugMode if the application is being debugged inside the Delphi IDE. 324 | Otherwise the default Delphi memory manager will be used (which is equivalent 325 | to the non-FullDebugMode FastMM since Delphi 2006.)} 326 | {.$define FullDebugModeInIDE} 327 | 328 | {Combines the FullDebugMode, LoadDebugDLLDynamically and 329 | DoNotInstallIfDLLMissing options. Consequently FastMM will only be installed 330 | (In FullDebugMode) when the FastMM_FullDebugMode.dll file is available. This 331 | is useful when the same executable will be distributed for both debugging as 332 | well as deployment.} 333 | {.$define FullDebugModeWhenDLLAvailable} 334 | 335 | {Group the options you use for release and debug versions below} 336 | {$ifdef Release} 337 | {Specify the options you use for release versions below} 338 | {.$undef FullDebugMode} 339 | {.$undef CheckHeapForCorruption} 340 | {.$define ASMVersion} 341 | {.$undef EnableMemoryLeakReporting} 342 | {.$undef UseOutputDebugString} 343 | {$else} 344 | {Specify the options you use for debugging below} 345 | {.$define FullDebugMode} 346 | {.$define EnableMemoryLeakReporting} 347 | {.$define UseOutputDebugString} 348 | {$endif} 349 | 350 | {--------------------Compilation Options For borlndmm.dll---------------------} 351 | {If you're compiling the replacement borlndmm.dll, set the defines below 352 | for the kind of dll you require.} 353 | 354 | {Set this option when compiling the borlndmm.dll} 355 | {.$define borlndmmdll} 356 | 357 | {Set this option if the dll will be used by the Delphi IDE} 358 | {.$define dllforide} 359 | 360 | {Set this option if you're compiling a debug dll} 361 | {.$define debugdll} 362 | 363 | {Do not change anything below this line} 364 | {$ifdef borlndmmdll} 365 | {$define AssumeMultiThreaded} 366 | {$undef HideExpectedLeaksRegisteredByPointer} 367 | {$undef RequireDebuggerPresenceForLeakReporting} 368 | {$undef RequireDebugInfoForLeakReporting} 369 | {$define DetectMMOperationsAfterUninstall} 370 | {$undef ManualLeakReportingControl} 371 | {$undef ShareMM} 372 | {$undef AttemptToUseSharedMM} 373 | {$ifdef dllforide} 374 | {$define NeverUninstall} 375 | {$define HideMemoryLeakHintMessage} 376 | {$undef RequireIDEPresenceForLeakReporting} 377 | {$ifndef debugdll} 378 | {$undef EnableMemoryLeakReporting} 379 | {$endif} 380 | {$else} 381 | {$define EnableMemoryLeakReporting} 382 | {$undef NeverUninstall} 383 | {$undef HideMemoryLeakHintMessage} 384 | {$define RequireIDEPresenceForLeakReporting} 385 | {$endif} 386 | {$ifdef debugdll} 387 | {$define FullDebugMode} 388 | {$define RawStackTraces} 389 | {$undef CatchUseOfFreedInterfaces} 390 | {$define LogErrorsToFile} 391 | {$define LogMemoryLeakDetailToFile} 392 | {$undef ClearLogFileOnStartup} 393 | {$else} 394 | {$undef FullDebugMode} 395 | {$endif} 396 | {$endif} 397 | 398 | {Move BCB related definitions here, because CB2006/CB2007 can build borlndmm.dll 399 | for tracing memory leaks in BCB applications with "Build with Dynamic RTL" 400 | switched on} 401 | {------------------------------Patch BCB Terminate----------------------------} 402 | {To enable the patching for BCB to make uninstallation and leak reporting 403 | possible, you may need to add "BCB" definition 404 | in "Project Options->Pascal/Delphi Compiler->Defines". 405 | (Thanks to JiYuan Xie for implementing this.)} 406 | 407 | {$ifdef BCB} 408 | {$ifdef CheckHeapForCorruption} 409 | {$define PatchBCBTerminate} 410 | {$else} 411 | {$ifdef DetectMMOperationsAfterUninstall} 412 | {$define PatchBCBTerminate} 413 | {$else} 414 | {$ifdef EnableMemoryLeakReporting} 415 | {$define PatchBCBTerminate} 416 | {$endif} 417 | {$endif} 418 | {$endif} 419 | 420 | {$ifdef PatchBCBTerminate} 421 | {$define CheckCppObjectType} 422 | {$undef CheckCppObjectTypeEnabled} 423 | 424 | {$ifdef CheckCppObjectType} 425 | {$define CheckCppObjectTypeEnabled} 426 | {$endif} 427 | 428 | {Turn off "CheckCppObjectTypeEnabled" option if neither "CheckHeapForCorruption" 429 | option or "EnableMemoryLeakReporting" option were defined.} 430 | {$ifdef CheckHeapForCorruption} 431 | {$else} 432 | {$ifdef EnableMemoryLeakReporting} 433 | {$else} 434 | {$undef CheckCppObjectTypeEnabled} 435 | {$endif} 436 | {$endif} 437 | {$endif} 438 | {$endif} 439 | -------------------------------------------------------------------------------- /sample/UrlParserSample.dproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | {F3BB24F2-5DB1-4DAB-8838-1653AEFFE8C0} 4 | 19.2 5 | VCL 6 | UrlParserSample.dpr 7 | True 8 | Release 9 | Win32 10 | 1 11 | Application 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | true 44 | Cfg_2 45 | true 46 | true 47 | 48 | 49 | .\$(Platform)\$(Config) 50 | .\$(Platform)\$(Config) 51 | false 52 | false 53 | false 54 | false 55 | false 56 | System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) 57 | $(BDS)\bin\delphi_PROJECTICON.ico 58 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 59 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 60 | UrlParserSample 61 | 1046 62 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 63 | FastMM4;$(DCC_UnitSearchPath) 64 | 65 | 66 | DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;XComponents;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;inetdb;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;ibxpress;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;vclib;rtl;Tee;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;TeeUI;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) 67 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 68 | Debug 69 | true 70 | 1033 71 | $(BDS)\bin\default_app.manifest 72 | 73 | 74 | DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;inetdb;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;ibxpress;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;vclib;rtl;Tee;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;TeeUI;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage) 75 | 76 | 77 | DEBUG;$(DCC_Define) 78 | true 79 | false 80 | true 81 | true 82 | true 83 | 84 | 85 | false 86 | true 87 | PerMonitorV2 88 | 89 | 90 | false 91 | RELEASE;$(DCC_Define) 92 | 0 93 | 0 94 | 95 | 96 | true 97 | PerMonitorV2 98 | true 99 | 1033 100 | 101 | 102 | 103 | MainSource 104 | 105 | 106 |
FMain
107 |
108 | 109 | 110 | Cfg_2 111 | Base 112 | 113 | 114 | Base 115 | 116 | 117 | Cfg_1 118 | Base 119 | 120 |
121 | 122 | Delphi.Personality.12 123 | Application 124 | 125 | 126 | 127 | UrlParserSample.dpr 128 | 129 | 130 | Microsoft Office 2000 Sample Automation Server Wrapper Components 131 | Microsoft Office XP Sample Automation Server Wrapper Components 132 | 133 | 134 | 135 | 136 | 137 | UrlParserSample.exe 138 | true 139 | 140 | 141 | 142 | 143 | UrlParserSample.exe 144 | true 145 | 146 | 147 | 148 | 149 | 1 150 | 151 | 152 | Contents\MacOS 153 | 1 154 | 155 | 156 | 0 157 | 158 | 159 | 160 | 161 | classes 162 | 1 163 | 164 | 165 | classes 166 | 1 167 | 168 | 169 | 170 | 171 | res\xml 172 | 1 173 | 174 | 175 | res\xml 176 | 1 177 | 178 | 179 | 180 | 181 | library\lib\armeabi-v7a 182 | 1 183 | 184 | 185 | 186 | 187 | library\lib\armeabi 188 | 1 189 | 190 | 191 | library\lib\armeabi 192 | 1 193 | 194 | 195 | 196 | 197 | library\lib\armeabi-v7a 198 | 1 199 | 200 | 201 | 202 | 203 | library\lib\mips 204 | 1 205 | 206 | 207 | library\lib\mips 208 | 1 209 | 210 | 211 | 212 | 213 | library\lib\armeabi-v7a 214 | 1 215 | 216 | 217 | library\lib\arm64-v8a 218 | 1 219 | 220 | 221 | 222 | 223 | library\lib\armeabi-v7a 224 | 1 225 | 226 | 227 | 228 | 229 | res\drawable 230 | 1 231 | 232 | 233 | res\drawable 234 | 1 235 | 236 | 237 | 238 | 239 | res\values 240 | 1 241 | 242 | 243 | res\values 244 | 1 245 | 246 | 247 | 248 | 249 | res\values-v21 250 | 1 251 | 252 | 253 | res\values-v21 254 | 1 255 | 256 | 257 | 258 | 259 | res\values 260 | 1 261 | 262 | 263 | res\values 264 | 1 265 | 266 | 267 | 268 | 269 | res\drawable 270 | 1 271 | 272 | 273 | res\drawable 274 | 1 275 | 276 | 277 | 278 | 279 | res\drawable-xxhdpi 280 | 1 281 | 282 | 283 | res\drawable-xxhdpi 284 | 1 285 | 286 | 287 | 288 | 289 | res\drawable-xxxhdpi 290 | 1 291 | 292 | 293 | res\drawable-xxxhdpi 294 | 1 295 | 296 | 297 | 298 | 299 | res\drawable-ldpi 300 | 1 301 | 302 | 303 | res\drawable-ldpi 304 | 1 305 | 306 | 307 | 308 | 309 | res\drawable-mdpi 310 | 1 311 | 312 | 313 | res\drawable-mdpi 314 | 1 315 | 316 | 317 | 318 | 319 | res\drawable-hdpi 320 | 1 321 | 322 | 323 | res\drawable-hdpi 324 | 1 325 | 326 | 327 | 328 | 329 | res\drawable-xhdpi 330 | 1 331 | 332 | 333 | res\drawable-xhdpi 334 | 1 335 | 336 | 337 | 338 | 339 | res\drawable-mdpi 340 | 1 341 | 342 | 343 | res\drawable-mdpi 344 | 1 345 | 346 | 347 | 348 | 349 | res\drawable-hdpi 350 | 1 351 | 352 | 353 | res\drawable-hdpi 354 | 1 355 | 356 | 357 | 358 | 359 | res\drawable-xhdpi 360 | 1 361 | 362 | 363 | res\drawable-xhdpi 364 | 1 365 | 366 | 367 | 368 | 369 | res\drawable-xxhdpi 370 | 1 371 | 372 | 373 | res\drawable-xxhdpi 374 | 1 375 | 376 | 377 | 378 | 379 | res\drawable-xxxhdpi 380 | 1 381 | 382 | 383 | res\drawable-xxxhdpi 384 | 1 385 | 386 | 387 | 388 | 389 | res\drawable-small 390 | 1 391 | 392 | 393 | res\drawable-small 394 | 1 395 | 396 | 397 | 398 | 399 | res\drawable-normal 400 | 1 401 | 402 | 403 | res\drawable-normal 404 | 1 405 | 406 | 407 | 408 | 409 | res\drawable-large 410 | 1 411 | 412 | 413 | res\drawable-large 414 | 1 415 | 416 | 417 | 418 | 419 | res\drawable-xlarge 420 | 1 421 | 422 | 423 | res\drawable-xlarge 424 | 1 425 | 426 | 427 | 428 | 429 | res\values 430 | 1 431 | 432 | 433 | res\values 434 | 1 435 | 436 | 437 | 438 | 439 | 1 440 | 441 | 442 | Contents\MacOS 443 | 1 444 | 445 | 446 | 0 447 | 448 | 449 | 450 | 451 | Contents\MacOS 452 | 1 453 | .framework 454 | 455 | 456 | Contents\MacOS 457 | 1 458 | .framework 459 | 460 | 461 | 0 462 | 463 | 464 | 465 | 466 | 1 467 | .dylib 468 | 469 | 470 | 1 471 | .dylib 472 | 473 | 474 | 1 475 | .dylib 476 | 477 | 478 | Contents\MacOS 479 | 1 480 | .dylib 481 | 482 | 483 | Contents\MacOS 484 | 1 485 | .dylib 486 | 487 | 488 | 0 489 | .dll;.bpl 490 | 491 | 492 | 493 | 494 | 1 495 | .dylib 496 | 497 | 498 | 1 499 | .dylib 500 | 501 | 502 | 1 503 | .dylib 504 | 505 | 506 | Contents\MacOS 507 | 1 508 | .dylib 509 | 510 | 511 | Contents\MacOS 512 | 1 513 | .dylib 514 | 515 | 516 | 0 517 | .bpl 518 | 519 | 520 | 521 | 522 | 0 523 | 524 | 525 | 0 526 | 527 | 528 | 0 529 | 530 | 531 | 0 532 | 533 | 534 | 0 535 | 536 | 537 | Contents\Resources\StartUp\ 538 | 0 539 | 540 | 541 | Contents\Resources\StartUp\ 542 | 0 543 | 544 | 545 | 0 546 | 547 | 548 | 549 | 550 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 551 | 1 552 | 553 | 554 | 555 | 556 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 557 | 1 558 | 559 | 560 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 561 | 1 562 | 563 | 564 | 565 | 566 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 567 | 1 568 | 569 | 570 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 571 | 1 572 | 573 | 574 | 575 | 576 | 1 577 | 578 | 579 | 1 580 | 581 | 582 | 1 583 | 584 | 585 | 586 | 587 | 1 588 | 589 | 590 | 1 591 | 592 | 593 | 1 594 | 595 | 596 | 597 | 598 | 1 599 | 600 | 601 | 1 602 | 603 | 604 | 1 605 | 606 | 607 | 608 | 609 | 1 610 | 611 | 612 | 1 613 | 614 | 615 | 1 616 | 617 | 618 | 619 | 620 | 1 621 | 622 | 623 | 1 624 | 625 | 626 | 1 627 | 628 | 629 | 630 | 631 | 1 632 | 633 | 634 | 1 635 | 636 | 637 | 1 638 | 639 | 640 | 641 | 642 | 1 643 | 644 | 645 | 1 646 | 647 | 648 | 1 649 | 650 | 651 | 652 | 653 | 1 654 | 655 | 656 | 1 657 | 658 | 659 | 1 660 | 661 | 662 | 663 | 664 | 1 665 | 666 | 667 | 1 668 | 669 | 670 | 1 671 | 672 | 673 | 674 | 675 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 676 | 1 677 | 678 | 679 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 680 | 1 681 | 682 | 683 | 684 | 685 | 1 686 | 687 | 688 | 1 689 | 690 | 691 | 1 692 | 693 | 694 | 695 | 696 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 697 | 1 698 | 699 | 700 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 701 | 1 702 | 703 | 704 | 705 | 706 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 707 | 1 708 | 709 | 710 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 711 | 1 712 | 713 | 714 | 715 | 716 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 717 | 1 718 | 719 | 720 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 721 | 1 722 | 723 | 724 | 725 | 726 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 727 | 1 728 | 729 | 730 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 731 | 1 732 | 733 | 734 | 735 | 736 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 737 | 1 738 | 739 | 740 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 741 | 1 742 | 743 | 744 | 745 | 746 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 747 | 1 748 | 749 | 750 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 751 | 1 752 | 753 | 754 | 755 | 756 | 1 757 | 758 | 759 | 1 760 | 761 | 762 | 1 763 | 764 | 765 | 766 | 767 | 1 768 | 769 | 770 | 1 771 | 772 | 773 | 1 774 | 775 | 776 | 777 | 778 | 1 779 | 780 | 781 | 1 782 | 783 | 784 | 1 785 | 786 | 787 | 788 | 789 | 1 790 | 791 | 792 | 1 793 | 794 | 795 | 1 796 | 797 | 798 | 799 | 800 | 1 801 | 802 | 803 | 1 804 | 805 | 806 | 1 807 | 808 | 809 | 810 | 811 | 1 812 | 813 | 814 | 1 815 | 816 | 817 | 1 818 | 819 | 820 | 821 | 822 | 1 823 | 824 | 825 | 1 826 | 827 | 828 | 1 829 | 830 | 831 | 832 | 833 | 1 834 | 835 | 836 | 1 837 | 838 | 839 | 1 840 | 841 | 842 | 843 | 844 | 1 845 | 846 | 847 | 1 848 | 849 | 850 | 1 851 | 852 | 853 | 854 | 855 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 856 | 1 857 | 858 | 859 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 860 | 1 861 | 862 | 863 | 864 | 865 | 1 866 | 867 | 868 | 1 869 | 870 | 871 | 1 872 | 873 | 874 | 875 | 876 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 877 | 1 878 | 879 | 880 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 881 | 1 882 | 883 | 884 | 885 | 886 | 1 887 | 888 | 889 | 1 890 | 891 | 892 | 1 893 | 894 | 895 | 896 | 897 | 1 898 | 899 | 900 | 1 901 | 902 | 903 | 1 904 | 905 | 906 | 907 | 908 | 1 909 | 910 | 911 | 1 912 | 913 | 914 | 1 915 | 916 | 917 | 918 | 919 | 1 920 | 921 | 922 | 1 923 | 924 | 925 | 1 926 | 927 | 928 | 929 | 930 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 931 | 1 932 | 933 | 934 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 935 | 1 936 | 937 | 938 | 939 | 940 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 941 | 1 942 | 943 | 944 | ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset 945 | 1 946 | 947 | 948 | 949 | 950 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 951 | 1 952 | 953 | 954 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 955 | 1 956 | 957 | 958 | 959 | 960 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 961 | 1 962 | 963 | 964 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 965 | 1 966 | 967 | 968 | 969 | 970 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 971 | 1 972 | 973 | 974 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 975 | 1 976 | 977 | 978 | 979 | 980 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 981 | 1 982 | 983 | 984 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 985 | 1 986 | 987 | 988 | 989 | 990 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 991 | 1 992 | 993 | 994 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 995 | 1 996 | 997 | 998 | 999 | 1000 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1001 | 1 1002 | 1003 | 1004 | ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset 1005 | 1 1006 | 1007 | 1008 | 1009 | 1010 | 1 1011 | 1012 | 1013 | 1 1014 | 1015 | 1016 | 1017 | 1018 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1019 | 1 1020 | 1021 | 1022 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1023 | 1 1024 | 1025 | 1026 | 1027 | 1028 | 1 1029 | 1030 | 1031 | 1 1032 | 1033 | 1034 | 1035 | 1036 | ..\ 1037 | 1 1038 | 1039 | 1040 | ..\ 1041 | 1 1042 | 1043 | 1044 | 1045 | 1046 | 1 1047 | 1048 | 1049 | 1 1050 | 1051 | 1052 | 1 1053 | 1054 | 1055 | 1056 | 1057 | ..\$(PROJECTNAME).launchscreen 1058 | 64 1059 | 1060 | 1061 | ..\$(PROJECTNAME).launchscreen 1062 | 64 1063 | 1064 | 1065 | 1066 | 1067 | 1 1068 | 1069 | 1070 | 1 1071 | 1072 | 1073 | 1 1074 | 1075 | 1076 | 1077 | 1078 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 1079 | 1 1080 | 1081 | 1082 | 1083 | 1084 | ..\ 1085 | 1 1086 | 1087 | 1088 | ..\ 1089 | 1 1090 | 1091 | 1092 | 1093 | 1094 | Contents 1095 | 1 1096 | 1097 | 1098 | Contents 1099 | 1 1100 | 1101 | 1102 | 1103 | 1104 | Contents\Resources 1105 | 1 1106 | 1107 | 1108 | Contents\Resources 1109 | 1 1110 | 1111 | 1112 | 1113 | 1114 | library\lib\armeabi-v7a 1115 | 1 1116 | 1117 | 1118 | library\lib\arm64-v8a 1119 | 1 1120 | 1121 | 1122 | 1 1123 | 1124 | 1125 | 1 1126 | 1127 | 1128 | 1 1129 | 1130 | 1131 | 1 1132 | 1133 | 1134 | Contents\MacOS 1135 | 1 1136 | 1137 | 1138 | Contents\MacOS 1139 | 1 1140 | 1141 | 1142 | 0 1143 | 1144 | 1145 | 1146 | 1147 | library\lib\armeabi-v7a 1148 | 1 1149 | 1150 | 1151 | 1152 | 1153 | 1 1154 | 1155 | 1156 | 1 1157 | 1158 | 1159 | 1160 | 1161 | Assets 1162 | 1 1163 | 1164 | 1165 | Assets 1166 | 1 1167 | 1168 | 1169 | 1170 | 1171 | Assets 1172 | 1 1173 | 1174 | 1175 | Assets 1176 | 1 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | True 1192 | False 1193 | 1194 | 1195 | 12 1196 | 1197 | 1198 | 1199 | 1200 |
1201 | --------------------------------------------------------------------------------