diff --git a/components/systools/examples/barcode (postnet)/expnbar.lpi b/components/systools/examples/barcode (postnet)/expnbar.lpi new file mode 100644 index 000000000..f0aa0b909 --- /dev/null +++ b/components/systools/examples/barcode (postnet)/expnbar.lpi @@ -0,0 +1,86 @@ + + + + + + + + + + + + + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <RequiredPackages Count="3"> + <Item1> + <PackageName Value="Printer4Lazarus"/> + </Item1> + <Item2> + <PackageName Value="laz_systools"/> + </Item2> + <Item3> + <PackageName Value="LCL"/> + </Item3> + </RequiredPackages> + <Units Count="2"> + <Unit0> + <Filename Value="expnbar.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="expnbaru.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmPostNet"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="expnbar"/> + </Target> + <SearchPaths> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/systools/examples/barcode (postnet)/expnbar.lpr b/components/systools/examples/barcode (postnet)/expnbar.lpr new file mode 100644 index 000000000..ede64f0f6 --- /dev/null +++ b/components/systools/examples/barcode (postnet)/expnbar.lpr @@ -0,0 +1,39 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +program expnbar; + +uses + Interfaces, + Forms, printer4lazarus, + expnbaru in 'expnbaru.pas' {frmPostNet}; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TfrmPostNet, frmPostNet); + Application.Run; +end. diff --git a/components/systools/examples/barcode (postnet)/expnbaru.lfm b/components/systools/examples/barcode (postnet)/expnbaru.lfm new file mode 100644 index 000000000..e7bef7131 --- /dev/null +++ b/components/systools/examples/barcode (postnet)/expnbaru.lfm @@ -0,0 +1,96 @@ +object frmPostNet: TfrmPostNet + Left = 291 + Height = 191 + Top = 145 + Width = 231 + BorderStyle = bsDialog + Caption = 'PostNet Barcode Example' + ClientHeight = 191 + ClientWidth = 231 + Color = clBtnFace + Font.Color = clWindowText + OnCreate = FormCreate + Position = poScreenCenter + LCLVersion = '1.9.0.0' + object Label1: TLabel + Left = 14 + Height = 15 + Top = 80 + Width = 51 + Caption = 'From Left' + ParentColor = False + end + object Label2: TLabel + Left = 128 + Height = 15 + Top = 80 + Width = 51 + Caption = 'From Top' + ParentColor = False + end + object BarCode1: TStPNBarCode + Left = 16 + Height = 16 + Top = 15 + Width = 199 + PostalCode = '12345' + end + object Label3: TLabel + Left = 76 + Height = 15 + Top = 44 + Width = 17 + Caption = 'ZIP' + ParentColor = False + end + object btnPrint: TButton + Left = 80 + Height = 25 + Top = 144 + Width = 75 + Caption = 'Print' + OnClick = btnPrintClick + TabOrder = 1 + end + object meZIP: TMaskEdit + Left = 103 + Height = 22 + Top = 40 + Width = 52 + CharCase = ecNormal + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Courier New' + MaxLength = 5 + ParentFont = False + TabOrder = 0 + OnChange = meZIPChange + EditMask = '00000;1;_' + Text = '12345' + SpaceChar = '_' + end + object edLeft: TFloatSpinEdit + Left = 15 + Height = 23 + Top = 98 + Width = 74 + Alignment = taRightJustify + Increment = 0.1 + MaxValue = 10 + MinValue = 0 + TabOrder = 2 + Value = 2.5 + end + object edTop: TFloatSpinEdit + Left = 128 + Height = 23 + Top = 98 + Width = 74 + Alignment = taRightJustify + Increment = 0.1 + MaxValue = 10 + MinValue = 0 + TabOrder = 3 + Value = 2.5 + end +end diff --git a/components/systools/examples/barcode (postnet)/expnbaru.pas b/components/systools/examples/barcode (postnet)/expnbaru.pas new file mode 100644 index 000000000..1bf352c3f --- /dev/null +++ b/components/systools/examples/barcode (postnet)/expnbaru.pas @@ -0,0 +1,116 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +(****************************************************************************** + +Enter a five-digit zip code and the inches to print from the left and top of +the page or envelope. Don't forget that laser printers can't print all the +way to the edge and so the value you enter must be adjusted accordingly. For +example, if you enter 5.0 for the "From Left" value and the printer has a +1/4" non-printable border, the bar code will be located 5.25" from the +actual edge of the paper. + +NOTE: Be sure to change the constant PrinterPixPerInch to match the + resolution of your printer. + +*******************************************************************************) + +unit expnbaru; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, MaskEdit, Spin, + + StBarPN; + +const + PrinterPixPerInch = 600; + +type + + { TfrmPostNet } + + TfrmPostNet = class(TForm) + btnPrint: TButton; + edLeft: TFloatSpinEdit; + Label1: TLabel; + Label2: TLabel; + edTop: TFloatSpinEdit; + BarCode1: TStPNBarCode; + meZIP: TMaskEdit; + Label3: TLabel; + procedure FormCreate(Sender: TObject); + procedure btnPrintClick(Sender: TObject); + procedure meZIPChange(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + frmPostNet: TfrmPostNet; + +implementation + +{$R *.lfm} + +uses + Printers, + StStrS; + +procedure TfrmPostNet.FormCreate(Sender: TObject); +begin + meZIP.Text := BarCode1.PostalCode; + //edLeft.Text := ' 5' + DecimalSeparator + '0'; + //edTop.Text := ' 3' + DecimalSeparator + '9'; +end; + +procedure TfrmPostNet.btnPrintClick(Sender: TObject); +var + P : TPoint; + L, + T : longint; +begin + L := Round(edLeft.Value * PrinterPixPerInch); + T := Round(edTop.Value * PrinterPixPerInch); + P := Point(L, T); + Printer.BeginDoc; + BarCode1.PaintToPrinterCanvas(Printer.Canvas, P); + Printer.EndDoc; +end; + +procedure TfrmPostNet.meZIPChange(Sender: TObject); +var + S : ShortString; +begin + S := TrimS(meZIP.Text); + if (Length(S) = 5) then + BarCode1.PostalCode := meZIP.Text; +end; + +end. diff --git a/components/systools/examples/barcode/ExBarCU.lfm b/components/systools/examples/barcode/ExBarCU.lfm new file mode 100644 index 000000000..93b168cf3 --- /dev/null +++ b/components/systools/examples/barcode/ExBarCU.lfm @@ -0,0 +1,840 @@ +object BarCodeForm: TBarCodeForm + Left = 214 + Height = 580 + Top = 137 + Width = 612 + Caption = 'Bar Code Component Example' + ClientHeight = 580 + ClientWidth = 612 + Color = clBtnFace + Font.Color = clWindowText + OnCreate = FormCreate + Position = poScreenCenter + LCLVersion = '1.9.0.0' + Scaled = False + object StDbBarCode1: TStDbBarCode + Left = 3 + Height = 65 + Top = 320 + Width = 606 + Anchors = [akTop, akLeft, akRight] + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcCode93 + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = False + Code128Subset = csCodeA + ShowCode = True + ShowGuardChars = False + TallGuardBars = False + DataField = 'Company' + DataSource = DataSource1 + end + object Label4: TLabel + Left = 3 + Height = 15 + Top = 301 + Width = 240 + Caption = 'Code 93 bar code attached to a database field' + ParentColor = False + end + object NB: TPageControl + Left = 3 + Height = 273 + Top = 3 + Width = 606 + ActivePage = TabSheet1 + Align = alTop + BorderSpacing.Around = 3 + TabIndex = 0 + TabOrder = 4 + OnChange = NBChange + object TabSheet1: TTabSheet + Caption = 'UPC/EAN' + ClientHeight = 245 + ClientWidth = 598 + object BarCode1: TStBarCode + Left = 8 + Height = 80 + Top = 56 + Width = 321 + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcUPC_A + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = False + Code = '12345678902' + Code128Subset = csCodeA + ShowCode = True + ShowGuardChars = False + TallGuardBars = True + end + object Label1: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 127 + Caption = 'Code: 11 or 12 Numeric ' + ParentColor = False + end + object edCode1: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + MaxLength = 12 + OnExit = btnUpdate1Click + TabOrder = 0 + Text = '012345678820' + end + object edSupp: TEdit + Left = 160 + Height = 23 + Top = 26 + Width = 49 + Enabled = False + MaxLength = 5 + OnExit = btnUpdate1Click + TabOrder = 2 + Text = '12345' + end + object rgType: TRadioGroup + Left = 336 + Height = 105 + Top = 25 + Width = 81 + AutoFill = True + Caption = 'Type' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 85 + ClientWidth = 77 + ItemIndex = 0 + Items.Strings = ( + 'UPC_A' + 'UPC_E' + 'EAN_13' + 'EAN_8' + ) + OnClick = btnUpdate1Click + TabOrder = 4 + end + object cbSupp: TCheckBox + Left = 160 + Height = 19 + Top = 7 + Width = 244 + Caption = 'Encode supplemental data: 2 or 5 Numeric' + OnClick = btnUpdate1Click + TabOrder = 1 + end + object cbTallGuardBars: TCheckBox + Left = 8 + Height = 19 + Top = 168 + Width = 98 + Caption = 'Tall guard bars' + Checked = True + OnClick = btnUpdate1Click + State = cbChecked + TabOrder = 6 + end + object cbShowCode: TCheckBox + Left = 8 + Height = 19 + Top = 144 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdate1Click + State = cbChecked + TabOrder = 5 + end + object btnUpdate1: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdate1Click + TabOrder = 3 + end + end + object TabSheet2: TTabSheet + Caption = 'Interleaved 2 of 5' + ClientHeight = 245 + ClientWidth = 575 + object BarCode2: TStBarCode + Left = 8 + Height = 80 + Top = 56 + Width = 321 + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcInterleaved2of5 + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = True + Code = '0123456789' + Code128Subset = csCodeA + ShowCode = True + ShowGuardChars = False + TallGuardBars = False + end + object Label2: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 83 + Caption = 'Code: Numeric ' + ParentColor = False + end + object cbBearerBars: TCheckBox + Left = 8 + Height = 19 + Top = 168 + Width = 78 + Caption = 'Bearer Bars' + Checked = True + OnClick = btnUpdate2Click + State = cbChecked + TabOrder = 3 + end + object cbShowCode2: TCheckBox + Left = 8 + Height = 19 + Top = 144 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdate2Click + State = cbChecked + TabOrder = 2 + end + object edCode2: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdate2Click + TabOrder = 0 + Text = '0123456789' + end + object btnUpdate2: TButton + Left = 224 + Height = 25 + Top = 24 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdate2Click + TabOrder = 1 + end + end + object TabSheet3: TTabSheet + Caption = 'Codabar' + ClientHeight = 245 + ClientWidth = 575 + object Label3: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 136 + Caption = 'Code: Numeric and -$:/.+' + ParentColor = False + end + object BarCode3: TStBarCode + Left = 8 + Height = 80 + Top = 56 + Width = 321 + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcCodabar + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = True + Code = 'c123456d' + Code128Subset = csCodeA + ShowCode = True + ShowGuardChars = False + TallGuardBars = False + end + object edCode3: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdate3Click + TabOrder = 0 + Text = 'c123456d' + end + object Button2: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdate3Click + TabOrder = 1 + end + object cbShowCode3: TCheckBox + Left = 8 + Height = 19 + Top = 144 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdate3Click + State = cbChecked + TabOrder = 2 + end + object cbShowGuardChars3: TCheckBox + Left = 8 + Height = 19 + Top = 168 + Width = 140 + Caption = 'Show guard characters' + OnClick = btnUpdate3Click + TabOrder = 3 + end + end + object TabSheet4: TTabSheet + Caption = 'Code 11' + ClientHeight = 245 + ClientWidth = 575 + object BarCode4: TStBarCode + Left = 8 + Height = 80 + Top = 56 + Width = 321 + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcCode11 + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = True + Code = '1234567890' + Code128Subset = csCodeA + ShowCode = True + ShowGuardChars = False + TallGuardBars = False + end + object Label5: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 111 + Caption = 'Code: Numeric and -' + ParentColor = False + end + object cbShowCode4: TCheckBox + Left = 8 + Height = 19 + Top = 144 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdate4Click + OnExit = btnUpdate4Click + State = cbChecked + TabOrder = 2 + end + object Button1: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdate4Click + TabOrder = 1 + end + object edCode4: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdate4Click + TabOrder = 0 + Text = '1234567890' + end + end + object TabSheet5: TTabSheet + Caption = 'Code 39' + ClientHeight = 245 + ClientWidth = 575 + object BarCode5: TStBarCode + Left = 8 + Height = 80 + Top = 56 + Width = 321 + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcCode39 + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = False + Code = '123456789' + Code128Subset = csCodeA + ShowCode = True + ShowGuardChars = False + TallGuardBars = False + end + object Label6: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 187 + Caption = 'Code: Alpha-Numeric and -. $/+%*' + ParentColor = False + end + object edCode5: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdate5Click + TabOrder = 0 + Text = '123456789' + end + object btnUpdate5: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdate5Click + TabOrder = 1 + end + object cbShowCode5: TCheckBox + Left = 8 + Height = 19 + Top = 144 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdate5Click + State = cbChecked + TabOrder = 2 + end + end + object TabSheet6: TTabSheet + Caption = 'Code 93' + ClientHeight = 245 + ClientWidth = 575 + object BarCode6: TStBarCode + Left = 8 + Height = 80 + Top = 56 + Width = 321 + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcCode93 + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = False + Code = 'CODE 93' + Code128Subset = csCodeA + ShowCode = True + ShowGuardChars = False + TallGuardBars = False + end + object Label7: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 187 + Caption = 'Code: Alpha-Numeric and -. $/+%*' + ParentColor = False + end + object edCode6: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdate6Click + TabOrder = 0 + Text = 'CODE 93' + end + object btnUpdate6: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdate6Click + TabOrder = 1 + end + object cbShowCode6: TCheckBox + Left = 8 + Height = 19 + Top = 144 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdate6Click + State = cbChecked + TabOrder = 2 + end + end + object TabSheet7: TTabSheet + Caption = 'Code 128' + ClientHeight = 245 + ClientWidth = 575 + object BarCode7: TStBarCode + Left = 8 + Height = 80 + Top = 56 + Width = 321 + Color = clWhite + ParentColor = False + AddCheckChar = True + BarCodeType = bcCode128 + BarColor = clBlack + BarToSpaceRatio = 1 + BarWidth = 12 + BearerBars = False + Code = '123456789ABCD' + Code128Subset = csCodeB + ShowCode = True + ShowGuardChars = False + TallGuardBars = False + end + object Label8: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 134 + Caption = 'Code: Fill Alpha-Numeric' + ParentColor = False + end + object edCode7: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdate7Click + TabOrder = 0 + Text = '123456789ABCD' + end + object btnUpdate7: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdate7Click + TabOrder = 1 + end + object cbShowCode7: TCheckBox + Left = 8 + Height = 19 + Top = 144 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdate7Click + State = cbChecked + TabOrder = 2 + end + end + object TabSheet8: TTabSheet + Caption = 'PDF417' + ClientHeight = 245 + ClientWidth = 575 + object Label9: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 134 + Caption = 'Code: Fill Alpha-Numeric' + ParentColor = False + end + object StPDF417Barcode1: TStPDF417Barcode + Left = 8 + Height = 121 + Top = 56 + Width = 457 + ParentColor = False + Alignment = taLeftJustify + BarWidth = 1 + Code = '123456789' + Caption = '123456789' + end + object edCodePDF417: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdatePDF417Click + TabOrder = 0 + Text = '123456789' + end + object btnUpdatePDF417: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdatePDF417Click + TabOrder = 1 + end + object cbShowCodePDF417: TCheckBox + Left = 8 + Height = 19 + Top = 184 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdatePDF417Click + State = cbChecked + TabOrder = 2 + end + object cbPDF417Truncated: TCheckBox + Left = 128 + Height = 19 + Top = 184 + Width = 74 + Caption = 'Truncated' + OnClick = btnUpdatePDF417Click + TabOrder = 3 + end + end + object TabSheet9: TTabSheet + Caption = 'MaxiCode' + ClientHeight = 245 + ClientWidth = 598 + object Label10: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 134 + Caption = 'Code: Fill Alpha-Numeric' + ParentColor = False + end + object Label11: TLabel + Left = 224 + Height = 15 + Top = 56 + Width = 87 + Caption = 'MaxiCode Mode' + ParentColor = False + end + object Label12: TLabel + Left = 224 + Height = 15 + Top = 152 + Width = 63 + Caption = 'Postal Code' + ParentColor = False + end + object Label13: TLabel + Left = 224 + Height = 15 + Top = 128 + Width = 74 + Caption = 'Country Code' + ParentColor = False + end + object Label14: TLabel + Left = 224 + Height = 15 + Top = 176 + Width = 67 + Caption = 'Service Class' + ParentColor = False + end + object StMaxiCodeBarcode1: TStMaxiCodeBarcode + Left = 8 + Top = 50 + ParentColor = False + CarrierPostalCode = '000000000' + HorPixelsPerMM = 4 + VerPixelsPerMM = 4 + Code = '123456789' + Caption = '123456789' + end + object edCodeMaxiCode: TEdit + Left = 8 + Height = 23 + Top = 26 + Width = 137 + OnExit = btnUpdateMaxiCodeClick + TabOrder = 0 + Text = '123456789' + end + object btnUpdateMaxiCode: TButton + Left = 224 + Height = 25 + Top = 25 + Width = 105 + Caption = 'Update Symbol' + OnClick = btnUpdateMaxiCodeClick + TabOrder = 1 + end + object cbShowCodeMaxiCode: TCheckBox + Left = 8 + Height = 19 + Top = 184 + Width = 78 + Caption = 'Show code' + Checked = True + OnClick = btnUpdateMaxiCodeClick + State = cbChecked + TabOrder = 8 + end + object radMCMode23: TRadioButton + Left = 232 + Height = 19 + Top = 72 + Width = 121 + Caption = 'Carrier Information' + OnClick = radMCMode23Click + TabOrder = 2 + end + object radMCMode4: TRadioButton + Left = 232 + Height = 19 + Top = 88 + Width = 110 + Caption = 'Standard Symbol' + Checked = True + OnClick = radMCMode4Click + TabOrder = 3 + TabStop = True + end + object radMCMode5: TRadioButton + Left = 232 + Height = 19 + Top = 104 + Width = 62 + Caption = 'Full EEC' + OnClick = radMCMode5Click + TabOrder = 4 + end + object edMCCountryCode: TEdit + Left = 309 + Height = 23 + Top = 125 + Width = 33 + Enabled = False + TabOrder = 5 + Text = '000' + end + object edMCPostalCode: TEdit + Left = 309 + Height = 23 + Top = 149 + Width = 73 + Enabled = False + TabOrder = 6 + Text = '000000000' + end + object edMCServiceClass: TEdit + Left = 309 + Height = 23 + Top = 173 + Width = 33 + Enabled = False + TabOrder = 7 + Text = '000' + end + end + end + object btnCopy: TButton + Left = 264 + Height = 25 + Top = 240 + Width = 75 + Caption = 'Copy' + OnClick = btnCopyClick + TabOrder = 3 + end + object btnPrint: TButton + Left = 16 + Height = 25 + Top = 240 + Width = 75 + Caption = 'Print Test' + OnClick = btnPrintClick + TabOrder = 0 + end + object btnClose: TButton + Left = 504 + Height = 25 + Top = 280 + Width = 99 + Anchors = [akTop, akLeft, akRight] + Cancel = True + Caption = 'Close' + ModalResult = 2 + OnClick = btnCloseClick + TabOrder = 5 + end + object DBGrid1: TDBGrid + Left = 3 + Height = 186 + Top = 392 + Width = 606 + Anchors = [akTop, akLeft, akRight, akBottom] + Color = clWindow + Columns = <> + DataSource = DataSource1 + TabOrder = 6 + TitleFont.Color = clWindowText + TitleFont.Height = -11 + TitleFont.Name = 'MS Sans Serif' + end + object btnSave: TButton + Left = 181 + Height = 25 + Top = 240 + Width = 75 + Caption = 'Save' + OnClick = btnSaveClick + TabOrder = 2 + end + object btnValidate: TButton + Left = 98 + Height = 25 + Top = 240 + Width = 75 + Caption = 'Validate' + OnClick = btnValidateClick + TabOrder = 1 + end + object PrintDialog1: TPrintDialog + left = 448 + top = 208 + end + object BufDataset1: TBufDataset + FieldDefs = <> + left = 192 + top = 432 + end + object DataSource1: TDataSource + DataSet = BufDataset1 + left = 320 + top = 432 + end +end diff --git a/components/systools/examples/barcode/ExBarCU.pas b/components/systools/examples/barcode/ExBarCU.pas new file mode 100644 index 000000000..eccf7be16 --- /dev/null +++ b/components/systools/examples/barcode/ExBarCU.pas @@ -0,0 +1,470 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +unit ExBarCU; + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, Printers, ExtCtrls, ComCtrls, Grids, + Db, BufDataset, DBCtrls, DBGrids, PrintersDlgs, + StBase, StBarC, StDbBarC, St2DBarC; + +type + + { TBarCodeForm } + + TBarCodeForm = class(TForm) + btnPrint: TButton; + BufDataset1: TBufDataset; + DataSource1: TDataSource; + PrintDialog1: TPrintDialog; + NB: TPageControl; + Tabsheet1: TTabsheet; + Tabsheet2: TTabsheet; + Tabsheet3: TTabsheet; + Tabsheet4: TTabsheet; + Tabsheet5: TTabsheet; + Tabsheet6: TTabsheet; + Tabsheet7: TTabsheet; + Tabsheet8: TTabsheet; + Tabsheet9: TTabsheet; + edCode1: TEdit; + edSupp: TEdit; + Label1: TLabel; + BarCode1: TStBarCode; + btnCopy: TButton; + BarCode2: TStBarCode; + BarCode5: TStBarCode; + rgType: TRadioGroup; + cbSupp: TCheckBox; + btnClose: TButton; + cbTallGuardBars: TCheckBox; + cbShowCode: TCheckBox; + btnUpdate1: TButton; + cbBearerBars: TCheckBox; + cbShowCode2: TCheckBox; + Label2: TLabel; + edCode2: TEdit; + btnUpdate2: TButton; + BarCode7: TStBarCode; + DBGrid1: TDBGrid; + btnSave: TButton; + BarCode6: TStBarCode; + StDbBarCode1: TStDbBarCode; + Label3: TLabel; + edCode3: TEdit; + Button2: TButton; + cbShowCode3: TCheckBox; + BarCode3: TStBarCode; + Label4: TLabel; + cbShowGuardChars3: TCheckBox; + cbShowCode4: TCheckBox; + BarCode4: TStBarCode; + Button1: TButton; + edCode4: TEdit; + Label5: TLabel; + Label6: TLabel; + edCode5: TEdit; + btnUpdate5: TButton; + cbShowCode5: TCheckBox; + Label7: TLabel; + edCode6: TEdit; + btnUpdate6: TButton; + cbShowCode6: TCheckBox; + Label8: TLabel; + edCode7: TEdit; + btnUpdate7: TButton; + cbShowCode7: TCheckBox; + Label9: TLabel; + edCodePDF417: TEdit; + btnUpdatePDF417: TButton; + cbShowCodePDF417: TCheckBox; + Label10: TLabel; + edCodeMaxiCode: TEdit; + btnUpdateMaxiCode: TButton; + cbShowCodeMaxiCode: TCheckBox; + radMCMode23: TRadioButton; + radMCMode4: TRadioButton; + radMCMode5: TRadioButton; + Label11: TLabel; + edMCCountryCode: TEdit; + edMCPostalCode: TEdit; + edMCServiceClass: TEdit; + Label12: TLabel; + Label13: TLabel; + Label14: TLabel; + cbPDF417Truncated: TCheckBox; + StPDF417Barcode1: TStPDF417Barcode; + StMaxiCodeBarcode1: TStMaxiCodeBarcode; + btnValidate: TButton; + procedure btnPrintClick(Sender: TObject); + procedure btnCopyClick(Sender: TObject); + procedure btnValidateClick(Sender: TObject); + procedure btnUpdate1Click(Sender: TObject); + procedure btnCloseClick(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure btnUpdate2Click(Sender: TObject); + procedure btnUpdate3Click(Sender: TObject); + procedure btnUpdate4Click(Sender: TObject); + procedure btnUpdate5Click(Sender: TObject); + procedure btnUpdate6Click(Sender: TObject); + procedure btnUpdate7Click(Sender: TObject); + procedure btnUpdatePDF417Click(Sender: TObject); + procedure btnUpdateMaxiCodeClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure radMCMode4Click(Sender: TObject); + procedure radMCMode23Click(Sender: TObject); + procedure radMCMode5Click(Sender: TObject); + procedure NBChange(Sender: TObject; NewTab: Integer; + var AllowChange: Boolean); + private + { Private declarations } + public + { Public declarations } + end; + +var + BarCodeForm: TBarCodeForm; + +implementation + +{$R *.lfm} + +procedure TBarCodeForm.btnPrintClick(Sender: TObject); +begin + if not PrintDialog1.Execute then + Exit; + Application.ProcessMessages; + + Screen.Cursor := crHourGlass; + try + Printer.BeginDoc; + try + Printer.Title := 'StBarCode'; + + BarCode1.BarcodeType := bcUPC_A; + BarCode1.Code := '52100014015'; + BarCode1.SupplementalCode := ''; + BarCode1.PaintToCanvasSize(Printer.Canvas, 0.5, 0.5, 0.5); + BarCode1.SupplementalCode := '12'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 3.0, 0.5, 0.5); + BarCode1.SupplementalCode := '12345'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 6.0, 0.5, 0.5); + + BarCode1.BarcodeType :=bcUPC_E; + BarCode1.Code := '173559'; + BarCode1.SupplementalCode := ''; + BarCode1.PaintToCanvasSize(Printer.Canvas, 0.5, 1.5, 0.5); + BarCode1.SupplementalCode := '12'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 3.0, 1.5, 0.5); + BarCode1.SupplementalCode := '12345'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 6.0, 1.5, 0.5); + + BarCode1.BarcodeType := bcEAN_13; + BarCode1.Code := '737622135746'; + BarCode1.SupplementalCode := ''; + BarCode1.PaintToCanvasSize(Printer.Canvas, 0.5, 2.5, 0.5); + BarCode1.SupplementalCode := '12'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 3.0, 2.5, 0.5); + BarCode1.SupplementalCode := '12345'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 6.0, 2.5, 0.5); + + BarCode1.BarcodeType := bcEAN_8; + BarCode1.Code := '1234567'; + BarCode1.SupplementalCode := ''; + BarCode1.PaintToCanvasSize(Printer.Canvas, 0.5, 3.5, 0.5); + BarCode1.SupplementalCode := '12'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 3.0, 3.5, 0.5); + BarCode1.SupplementalCode := '12345'; + BarCode1.PaintToCanvasSize(Printer.Canvas, 6.0, 3.5, 0.5); + + BarCode2.BarcodeType := bcInterleaved2of5; + BarCode2.Code := '0123456789'; + BarCode2.PaintToCanvasSize(Printer.Canvas, 0.5, 4.5, 0.5); + + BarCode3.BarCodeType := bcCodabar; + BarCode3.Code := 'c1234567890d'; + BarCode3.PaintToCanvasSize(Printer.Canvas, 3.0, 4.5, 0.5); + + BarCode4.BarCodeType := bcCode11; + BarCode4.Code := '0123456-12'; + BarCode4.PaintToCanvasSize(Printer.Canvas, 5.0, 4.5, 0.5); + + BarCode5.BarCodeType := bcCode39; + BarCode5.Code := '1234567890ABCDEFG'; + BarCode5.PaintToCanvasSize(Printer.Canvas, 0.5, 5.5, 0.5); + BarCode5.Code := '4-976 SUGARLOAF HWY'; + BarCode5.PaintToCanvasSize(Printer.Canvas, 4.5, 5.5, 0.5); + + BarCode6.BarCodeType := bcCode93; + BarCode6.Code := 'CODE 93'; + BarCode6.PaintToCanvasSize(Printer.Canvas, 0.5, 6.5, 0.5); + + BarCode7.BarCodeType := bcCode128; + BarCode7.Code128Subset := csCodeA; + BarCode7.Code := 'CODE 128'; + BarCode7.Validate(True); + BarCode7.PaintToCanvasSize(Printer.Canvas, 3.0, 6.5, 0.5); + + StMaxiCodeBarcode1.Mode := cmMode5; + StMaxiCodeBarcode1.Code := 'MaxiCode'; + StMaxiCodeBarcode1.Caption := 'MaxiCode'; + StMaxiCodeBarcode1.PaintToPrinterCanvasSize (Printer.Canvas, 0.5, 7.5, 1); + + StPDF417Barcode1.Code := 'PDF417'; + StPDF417Barcode1.Caption := 'PDF417'; + StPDF417Barcode1.PaintToPrinterCanvasSize (Printer.Canvas, 3.0, 7.5, 1); + finally + if not Printer.Aborted then + Printer.EndDoc; + end; + finally + Screen.Cursor := crDefault; + end; +end; + +procedure TBarCodeForm.btnCopyClick(Sender: TObject); +begin + case NB.PageIndex of + 0 : BarCode1.CopyToClipboard; + 1 : BarCode2.CopyToClipboard; + 2 : BarCode3.CopyToClipboard; + 3 : BarCode4.CopyToClipboard; + 4 : BarCode5.CopyToClipboard; + 5 : BarCode6.CopyToClipboard; + 6 : BarCode7.CopyToClipboard; + 7 : StPDF417Barcode1.CopyToClipboard; + 8 : StMaxiCodeBarcode1.CopyToClipboard; + end; +end; + +procedure TBarCodeForm.btnValidateClick(Sender: TObject); +begin + case NB.PageIndex of + 0 : BarCode1.Validate(True); + 1 : BarCode2.Validate(True); + 2 : BarCode3.Validate(True); + 3 : BarCode4.Validate(True); + 4 : BarCode5.Validate(True); + 5 : BarCode6.Validate(True); + 6 : BarCode7.Validate(True); + end; +end; + +procedure TBarCodeForm.FormCreate(Sender: TObject); + procedure PostDataset(ACustNo: Integer; ACompany: String); + begin + with BufDataset1 do begin + Append; + FieldByName('CustNo').AsInteger := ACustNo; + FieldByName('Company').AsString := ACompany; + Post; + end; + end; + +begin + BufDataset1.FieldDefs.Add('CustNo', ftInteger); + BufDataset1.FieldDefs.Add('Company', ftString, 32); + BufDataset1.CreateDataset; + BufDataset1.Active := true; + PostDataset(1221, 'Kauai Dive Shoppe'); + PostDataset(1231, 'Unisco'); + PostDataset(1351, 'Sight Diver'); + PostDataset(1354, 'Cayman Divers World Unlimited'); + PostDataset(1356, 'Tom Sawyer Diving Centre'); + PostDataset(1380, 'Blue Jack Aqua Center'); + PostDataset(1384, 'VIP Divers Club'); + PostDataset(1510, 'Ocean Paradise'); + PostDataset(1513, 'Fantastique Aquatica'); + PostDataset(1551, 'Marmot Divers Club'); + PostDataset(1560, 'The Depth Charge'); + PostDataset(1563, 'Blue Sports'); + PostDataset(1624, 'Makai SCUBA Club'); + PostDataset(1645, 'Action Club'); + PostDataset(1651, 'Jamaica SCUBA Centre'); +end; + +procedure TBarCodeForm.btnCloseClick(Sender: TObject); +begin + Close; +end; + +procedure TBarCodeForm.btnSaveClick(Sender: TObject); +begin + case NB.PageIndex of + 0 : BarCode1.SaveToFile('UPCEAN.bmp'); + 1 : BarCode2.SaveToFile('I2of5.bmp'); + 2 : BarCode3.SaveToFile('Codabar.bmp'); + 3 : BarCode4.SaveToFile('Code11.bmp'); + 4 : BarCode5.SaveToFile('Code39.bmp'); + 5 : BarCode6.SaveToFile('Code93.bmp'); + 6 : BarCode7.SaveToFile('Code128.bmp'); + 7 : StPDF417Barcode1.SaveToFile ('PDF417.bmp'); + 8 : StMaxiCodeBarcode1.SaveToFile ('MaxiCode.bmp'); + end; +end; + +procedure TBarCodeForm.btnUpdate1Click(Sender: TObject); +begin + case rgType.ItemIndex of + 0 : begin + BarCode1.BarcodeType := bcUPC_A; + edCode1.MaxLength := 12; + edCode1.Text := Copy(edCode1.Text, 1, 12); + Label1.Caption := 'Code: 11 or 12 Numeric '; + end; + 1 : begin + BarCode1.BarcodeType := bcUPC_E; + edCode1.MaxLength := 6; + Label1.Caption := 'Code: 6 Numeric '; + edCode1.Text := Copy(edCode1.Text, 1, 6); + end; + 2 : begin + BarCode1.BarcodeType := bcEAN_13; + edCode1.MaxLength := 13; + Label1.Caption := 'Code: 12 or 13 Numeric '; + edCode1.Text := Copy(edCode1.Text, 1, 13); + end; + 3 : begin + BarCode1.BarcodeType := bcEAN_8; + edCode1.MaxLength := 8; + Label1.Caption := 'Code: 7 or 8 Numeric '; + edCode1.Text := Copy(edCode1.Text, 1, 8); + end; + end; + BarCode1.ShowCode := cbShowCode.Checked; + BarCode1.TallGuardBars := cbTallGuardBars.Checked; + BarCode1.Code := edCode1.Text; + if cbSupp.Checked then begin + BarCode1.SupplementalCode := edSupp.Text; + edSupp.Enabled := True; + end else begin + BarCode1.SupplementalCode := ''; + edSupp.Enabled := False; + end; +end; + +procedure TBarCodeForm.btnUpdate2Click(Sender: TObject); +begin + BarCode2.Code := edCode2.Text; + BarCode2.ShowCode := cbShowCode2.Checked; + BarCode2.BearerBars := cbBearerBars.Checked; +end; + +procedure TBarCodeForm.btnUpdate3Click(Sender: TObject); +begin + BarCode3.Code := edCode3.Text; + BarCode3.ShowCode := cbShowCode3.Checked; + BarCode3.ShowGuardChars := cbShowGuardChars3.Checked; +end; + +procedure TBarCodeForm.btnUpdate4Click(Sender: TObject); +begin + BarCode4.Code := edCode4.Text; + BarCode4.ShowCode := cbShowCode4.Checked; +end; + +procedure TBarCodeForm.btnUpdate5Click(Sender: TObject); +begin + BarCode5.Code := edCode5.Text; + BarCode5.ShowCode := cbShowCode5.Checked; +end; + +procedure TBarCodeForm.btnUpdate6Click(Sender: TObject); +begin + BarCode6.Code := edCode6.Text; + BarCode6.ShowCode := cbShowCode6.Checked; +end; + +procedure TBarCodeForm.btnUpdate7Click(Sender: TObject); +begin + BarCode7.Code := edCode7.Text; + BarCode7.ShowCode := cbShowCode7.Checked; +end; + +procedure TBarCodeForm.btnUpdatePDF417Click(Sender: TObject); +begin + StPDF417Barcode1.Truncated := cbPDF417Truncated.Checked; + StPDF417BarCode1.Code := edCodePDF417.Text; + if cbShowCodePDF417.Checked then + StPDF417BarCode1.Caption := edCodePDF417.Text + else + StPDF417BarCode1.Caption := ''; +end; + +procedure TBarCodeForm.btnUpdateMaxiCodeClick(Sender: TObject); +begin + StMaxiCodeBarCode1.Code := edCodeMaxiCode.Text; + StMaxiCodeBarCode1.CarrierCountryCode := StrToInt (edMCCountryCode.Text); + StMaxiCodeBarCode1.CarrierPostalCode := edMCPostalCode.Text; + StMaxiCodeBarCode1.CarrierServiceClass := StrToInt (edMCServiceClass.Text); + if cbShowCodeMaxiCode.Checked then + StMaxiCodeBarCode1.Caption := edCodeMaxiCode.Text + else + StMaxiCodeBarCode1.Caption := ''; +end; + +procedure TBarCodeForm.radMCMode4Click(Sender: TObject); +begin + edMCServiceClass.Enabled := False; + edMCPostalCode.Enabled := False; + edMCCountryCode.Enabled := False; + StMaxiCodeBarCode1.Mode := cmMode4; + btnUpdateMaxiCodeClick (Sender); +end; + +procedure TBarCodeForm.radMCMode23Click(Sender: TObject); +begin + edMCServiceClass.Enabled := True; + edMCPostalCode.Enabled := True; + edMCCountryCode.Enabled := True; + StMaxiCodeBarCode1.Mode := cmMode2; + btnUpdateMaxiCodeClick (Sender); +end; + +procedure TBarCodeForm.radMCMode5Click(Sender: TObject); +begin + edMCServiceClass.Enabled := False; + edMCPostalCode.Enabled := False; + edMCCountryCode.Enabled := False; + StMaxiCodeBarCode1.Mode := cmMode5; + btnUpdateMaxiCodeClick (Sender); +end; + +procedure TBarCodeForm.NBChange(Sender: TObject; NewTab: Integer; + var AllowChange: Boolean); +begin + if (NewTab = 7) or (NewTab = 8) then + btnValidate.Enabled := False + else + btnValidate.Enabled := True; +end; + +end. + + + diff --git a/components/systools/examples/barcode/Exbarc.lpi b/components/systools/examples/barcode/Exbarc.lpi new file mode 100644 index 000000000..a9e4cbd3c --- /dev/null +++ b/components/systools/examples/barcode/Exbarc.lpi @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <General> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="Exbarc"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <Icon Value="0"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <RequiredPackages Count="5"> + <Item1> + <PackageName Value="FCL"/> + </Item1> + <Item2> + <PackageName Value="Printer4Lazarus"/> + </Item2> + <Item3> + <PackageName Value="laz_systoolsdb"/> + </Item3> + <Item4> + <PackageName Value="laz_systools"/> + </Item4> + <Item5> + <PackageName Value="LCL"/> + </Item5> + </RequiredPackages> + <Units Count="2"> + <Unit0> + <Filename Value="Exbarc.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="ExBarC"/> + </Unit0> + <Unit1> + <Filename Value="ExBarCU.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="BarCodeForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="Exbarc"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/systools/examples/barcode/Exbarc.lpr b/components/systools/examples/barcode/Exbarc.lpr new file mode 100644 index 000000000..48cd093c8 --- /dev/null +++ b/components/systools/examples/barcode/Exbarc.lpr @@ -0,0 +1,40 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +program ExBarC; + +uses + Interfaces, + Forms, printer4lazarus, + ExBarCU in 'ExBarCU.pas' {BarCodeForm}; + +{$R *.res} + +begin + RequireDerivedFormResource := True; + Application.Initialize; + Application.CreateForm(TBarCodeForm, BarCodeForm); + Application.Run; +end. diff --git a/components/systools/examples/expression/exexpr.lpi b/components/systools/examples/expression/exexpr.lpi new file mode 100644 index 000000000..6300d8f8b --- /dev/null +++ b/components/systools/examples/expression/exexpr.lpi @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <General> + <Flags> + <UseDefaultCompilerOptions Value="True"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="exexpr"/> + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="laz_systools"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="2"> + <Unit0> + <Filename Value="exexpr.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="ExExpr"/> + </Unit0> + <Unit1> + <Filename Value="exexpru.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="StDlg"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="ExExprU"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="exexpr"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/systools/examples/expression/exexpr.lpr b/components/systools/examples/expression/exexpr.lpr new file mode 100644 index 000000000..7aef435dd --- /dev/null +++ b/components/systools/examples/expression/exexpr.lpr @@ -0,0 +1,41 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +program ExExpr; + +uses + Forms, Interfaces, lclversion, + ExExprU in 'ExExprU.pas' {StDlg}; + +{$R *.res} + +begin + {$IF lcl_fullversion >= 1080000} + Application.Scaled := True; + {$ENDIF} + Application.Initialize; + Application.CreateForm(TStDlg, StDlg); + Application.Run; +end. diff --git a/components/systools/examples/expression/exexpru.lfm b/components/systools/examples/expression/exexpru.lfm new file mode 100644 index 000000000..f05dbc0c5 --- /dev/null +++ b/components/systools/examples/expression/exexpru.lfm @@ -0,0 +1,477 @@ +object StDlg: TStDlg + Left = 693 + Height = 270 + Top = 379 + Width = 462 + BorderStyle = bsDialog + Caption = 'Expression Evaluator (StExpr) Example' + ClientHeight = 270 + ClientWidth = 462 + Color = clBtnFace + Font.Color = clWindowText + Position = poScreenCenter + LCLVersion = '1.9.0.0' + object Label1: TLabel + Left = 16 + Height = 15 + Top = 16 + Width = 128 + Caption = 'Expression to evaluate:' + Font.Color = clWindowText + Font.Style = [fsBold] + ParentColor = False + ParentFont = False + end + object Label2: TLabel + Left = 16 + Height = 15 + Top = 63 + Width = 38 + Caption = 'Result:' + Font.Color = clWindowText + Font.Style = [fsBold] + ParentColor = False + ParentFont = False + end + object Panel2: TPanel + Left = 204 + Height = 141 + Top = 112 + Width = 165 + BevelOuter = bvLowered + ClientHeight = 141 + ClientWidth = 165 + TabOrder = 4 + object DivBtn: TBitBtn + Left = 123 + Height = 28 + Top = 9 + Width = 35 + Caption = '/' + Font.Color = clRed + OnClick = DivBtnClick + ParentFont = False + TabOrder = 15 + end + object MulBtn: TBitBtn + Left = 123 + Height = 28 + Top = 42 + Width = 35 + Caption = '*' + Font.Color = clRed + OnClick = MulBtnClick + ParentFont = False + TabOrder = 14 + end + object MinusBtn: TBitBtn + Left = 123 + Height = 28 + Top = 74 + Width = 35 + Caption = '-' + Font.Color = clRed + OnClick = MinusBtnClick + ParentFont = False + TabOrder = 13 + end + object PlusBtn: TBitBtn + Left = 123 + Height = 28 + Top = 107 + Width = 35 + Caption = '+' + Font.Color = clRed + OnClick = PlusBtnClick + ParentFont = False + TabOrder = 12 + end + object EBtn: TBitBtn + Left = 45 + Height = 28 + Top = 107 + Width = 35 + Caption = 'E' + Font.Color = clBlue + OnClick = EBtnClick + ParentFont = False + TabOrder = 11 + end + object Nr3Btn: TBitBtn + Left = 84 + Height = 28 + Top = 74 + Width = 35 + Caption = '3' + Font.Color = clBlue + OnClick = Nr3BtnClick + ParentFont = False + TabOrder = 3 + end + object Nr6Btn: TBitBtn + Left = 84 + Height = 28 + Top = 42 + Width = 35 + Caption = '6' + Font.Color = clBlue + OnClick = Nr6BtnClick + ParentFont = False + TabOrder = 6 + end + object Nr9Btn: TBitBtn + Left = 84 + Height = 28 + Top = 9 + Width = 35 + Caption = '9' + Font.Color = clBlue + OnClick = Nr9BtnClick + ParentFont = False + TabOrder = 9 + end + object DotBtn: TBitBtn + Left = 84 + Height = 28 + Top = 107 + Width = 35 + Caption = '.' + Font.Color = clBlue + OnClick = DotBtnClick + ParentFont = False + TabOrder = 10 + end + object Nr2Btn: TBitBtn + Left = 45 + Height = 28 + Top = 74 + Width = 35 + Caption = '2' + Font.Color = clBlue + OnClick = Nr2BtnClick + ParentFont = False + TabOrder = 2 + end + object Nr5Btn: TBitBtn + Left = 45 + Height = 28 + Top = 42 + Width = 35 + Caption = '5' + Font.Color = clBlue + OnClick = Nr5BtnClick + ParentFont = False + TabOrder = 5 + end + object Nr8Btn: TBitBtn + Left = 45 + Height = 28 + Top = 9 + Width = 35 + Caption = '8' + Font.Color = clBlue + OnClick = Nr8BtnClick + ParentFont = False + TabOrder = 8 + end + object Nr0Btn: TBitBtn + Left = 6 + Height = 28 + Top = 107 + Width = 35 + Caption = '0' + Font.Color = clBlue + OnClick = Nr0BtnClick + ParentFont = False + TabOrder = 0 + end + object Nr1Btn: TBitBtn + Left = 6 + Height = 28 + Top = 74 + Width = 35 + Caption = '1' + Font.Color = clBlue + OnClick = Nr1BtnClick + ParentFont = False + TabOrder = 1 + end + object Nr4Btn: TBitBtn + Left = 6 + Height = 28 + Top = 42 + Width = 35 + Caption = '4' + Font.Color = clBlue + OnClick = Nr4BtnClick + ParentFont = False + TabOrder = 4 + end + object Nr7Btn: TBitBtn + Left = 6 + Height = 28 + Top = 9 + Width = 35 + Caption = '7' + Font.Color = clBlue + OnClick = Nr7BtnClick + ParentFont = False + TabOrder = 7 + end + end + object Panel1: TPanel + Left = 24 + Height = 141 + Top = 112 + Width = 169 + BevelOuter = bvLowered + ClientHeight = 141 + ClientWidth = 169 + TabOrder = 5 + object SqrtBtn: TBitBtn + Left = 48 + Height = 28 + Top = 106 + Width = 35 + Caption = 'sqrt' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = SqrtBtnClick + ParentFont = False + TabOrder = 9 + end + object PiBtn: TBitBtn + Left = 9 + Height = 28 + Top = 9 + Width = 35 + Caption = 'pi' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = PiBtnClick + ParentFont = False + TabOrder = 15 + end + object ExpBtn: TBitBtn + Left = 87 + Height = 28 + Top = 74 + Width = 35 + Caption = 'Exp' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = ExpBtnClick + ParentFont = False + TabOrder = 7 + end + object PowerBtn: TBitBtn + Left = 48 + Height = 28 + Top = 41 + Width = 35 + Caption = '^' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = PowerBtnClick + ParentFont = False + TabOrder = 11 + end + object CommaBtn: TBitBtn + Left = 126 + Height = 28 + Top = 9 + Width = 35 + Caption = ',' + Enabled = False + Font.Color = clFuchsia + Font.Height = -11 + OnClick = CommaBtnClick + ParentFont = False + TabOrder = 2 + end + object CosBtn: TBitBtn + Left = 9 + Height = 28 + Top = 73 + Width = 35 + Caption = 'cos' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = CosBtnClick + ParentFont = False + TabOrder = 13 + end + object LnBtn: TBitBtn + Left = 87 + Height = 28 + Top = 42 + Width = 35 + Caption = 'ln' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = LnBtnClick + ParentFont = False + TabOrder = 8 + end + object SqrBtn: TBitBtn + Left = 48 + Height = 28 + Top = 74 + Width = 35 + Caption = 'sqr' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = SqrBtnClick + ParentFont = False + TabOrder = 10 + end + object RParBtn: TBitBtn + Left = 87 + Height = 28 + Top = 9 + Width = 35 + Caption = ')' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = RParBtnClick + ParentFont = False + TabOrder = 1 + end + object ArctanBtn: TBitBtn + Left = 9 + Height = 28 + Top = 106 + Width = 35 + Caption = 'arctan' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = ArctanBtnClick + ParentFont = False + TabOrder = 12 + end + object IntBtn: TBitBtn + Left = 126 + Height = 28 + Top = 106 + Width = 35 + Caption = 'int' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = IntBtnClick + ParentFont = False + TabOrder = 3 + end + object SinBtn: TBitBtn + Left = 9 + Height = 28 + Top = 41 + Width = 35 + Caption = 'sin' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = SinBtnClick + ParentFont = False + TabOrder = 14 + end + object LParBtn: TBitBtn + Left = 48 + Height = 28 + Top = 9 + Width = 35 + Caption = '(' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = LParBtnClick + ParentFont = False + TabOrder = 0 + end + object AbsBtn: TBitBtn + Left = 87 + Height = 28 + Top = 106 + Width = 35 + Caption = 'abs' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = AbsBtnClick + ParentFont = False + TabOrder = 6 + end + object FracBtn: TBitBtn + Left = 126 + Height = 28 + Top = 74 + Width = 35 + Caption = 'frac' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = FracBtnClick + ParentFont = False + TabOrder = 4 + end + object RoundBtn: TBitBtn + Left = 126 + Height = 28 + Top = 41 + Width = 35 + Caption = 'round' + Font.Color = clFuchsia + Font.Height = -11 + OnClick = RoundBtnClick + ParentFont = False + TabOrder = 5 + end + end + object ResultEdit: TEdit + Left = 16 + Height = 23 + Top = 79 + Width = 432 + Color = clBtnFace + ReadOnly = True + TabStop = False + TabOrder = 6 + end + object EvaluateBtn: TBitBtn + Left = 380 + Height = 25 + Top = 116 + Width = 65 + Caption = 'Evaluate' + Default = True + Font.Color = clMaroon + OnClick = EvaluateBtnClick + ParentFont = False + TabOrder = 1 + end + object ClearBtn: TBitBtn + Left = 380 + Height = 25 + Top = 148 + Width = 65 + Caption = 'Clear' + Font.Color = clMaroon + OnClick = ClearBtnClick + ParentFont = False + TabOrder = 2 + end + object ExprEdit: TStExpressionEdit + Left = 16 + Height = 23 + Top = 32 + Width = 433 + TabOrder = 0 + OnError = ExprEditError + end + object BSBtn: TBitBtn + Left = 380 + Height = 25 + Top = 180 + Width = 65 + Caption = 'Backspace' + Font.Color = clMaroon + OnClick = BSBtnClick + ParentFont = False + TabOrder = 3 + end +end diff --git a/components/systools/examples/expression/exexpru.pas b/components/systools/examples/expression/exexpru.pas new file mode 100644 index 000000000..6b0a2e009 --- /dev/null +++ b/components/systools/examples/expression/exexpru.pas @@ -0,0 +1,368 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{$mode delphi} + +unit ExExprU; + +interface + +uses + {$IFDEF FPC} +// LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, + {$ENDIF} + SysUtils, Classes, Graphics, Controls, + Forms, Dialogs, ExtCtrls, Buttons, StdCtrls, + + StBase, StConst, StExpr; + +type + TStDlg = class(TForm) + Label1: TLabel; + ResultEdit: TEdit; + Label2: TLabel; + EvaluateBtn: TBitBtn; + ClearBtn: TBitBtn; + Panel1: TPanel; + Panel2: TPanel; + ExprEdit: TStExpressionEdit; + DivBtn: TBitBtn; + MulBtn: TBitBtn; + MinusBtn: TBitBtn; + PlusBtn: TBitBtn; + EBtn: TBitBtn; + Nr3Btn: TBitBtn; + Nr6Btn: TBitBtn; + Nr9Btn: TBitBtn; + DotBtn: TBitBtn; + Nr2Btn: TBitBtn; + Nr5Btn: TBitBtn; + Nr8Btn: TBitBtn; + Nr0Btn: TBitBtn; + Nr1Btn: TBitBtn; + Nr4Btn: TBitBtn; + Nr7Btn: TBitBtn; + SqrtBtn: TBitBtn; + PiBtn: TBitBtn; + ExpBtn: TBitBtn; + PowerBtn: TBitBtn; + CommaBtn: TBitBtn; + CosBtn: TBitBtn; + LnBtn: TBitBtn; + SqrBtn: TBitBtn; + RParBtn: TBitBtn; + ArctanBtn: TBitBtn; + IntBtn: TBitBtn; + SinBtn: TBitBtn; + LParBtn: TBitBtn; + AbsBtn: TBitBtn; + FracBtn: TBitBtn; + RoundBtn: TBitBtn; + BSBtn: TBitBtn; + procedure LParBtnClick(Sender: TObject); + procedure RParBtnClick(Sender: TObject); + procedure CommaBtnClick(Sender: TObject); + procedure PowerBtnClick(Sender: TObject); + procedure AbsBtnClick(Sender: TObject); + procedure ArctanBtnClick(Sender: TObject); + procedure CosBtnClick(Sender: TObject); + procedure ExpBtnClick(Sender: TObject); + procedure FracBtnClick(Sender: TObject); + procedure IntBtnClick(Sender: TObject); + procedure LnBtnClick(Sender: TObject); + procedure PiBtnClick(Sender: TObject); + procedure RoundBtnClick(Sender: TObject); + procedure SinBtnClick(Sender: TObject); + procedure SqrBtnClick(Sender: TObject); + procedure SqrtBtnClick(Sender: TObject); + procedure Nr0BtnClick(Sender: TObject); + procedure Nr1BtnClick(Sender: TObject); + procedure Nr2BtnClick(Sender: TObject); + procedure Nr3BtnClick(Sender: TObject); + procedure Nr4BtnClick(Sender: TObject); + procedure Nr5BtnClick(Sender: TObject); + procedure Nr6BtnClick(Sender: TObject); + procedure Nr7BtnClick(Sender: TObject); + procedure Nr8BtnClick(Sender: TObject); + procedure Nr9BtnClick(Sender: TObject); + procedure DotBtnClick(Sender: TObject); + procedure EBtnClick(Sender: TObject); + procedure PlusBtnClick(Sender: TObject); + procedure MinusBtnClick(Sender: TObject); + procedure MulBtnClick(Sender: TObject); + procedure DivBtnClick(Sender: TObject); + procedure EvaluateBtnClick(Sender: TObject); + procedure ClearBtnClick(Sender: TObject); + procedure ExprEditError(Sender: TObject; ErrorNumber: Longint; + const ErrorStr: String); + procedure BSBtnClick(Sender: TObject); + private + procedure AddExpr(Add : string; Parens : Boolean); + end; + +var + StDlg: TStDlg; + +implementation + +{$R *.lfm} + +procedure TStDlg.AddExpr(add : string; parens : boolean); +var + position, sellen : integer; + temp : string; +begin + position := ExprEdit.SelStart+1; + sellen := ExprEdit.SelLength; + temp := ExprEdit.Text; + + if (parens) then begin + add := add+'('; + if (sellen > 0) then + {surround the selection with the parentheses} + insert(')', temp, position+sellen) + else + add := add+')'; + end; + insert(add, temp, position); + + ExprEdit.Text := temp; + ExprEdit.SetFocus; + + if (parens) then begin + if (sellen > 0) then + {position after the add} + ExprEdit.SelStart := position+sellen+length(add) + else + {position before last parenthesis} + ExprEdit.SelStart := position+length(add)-2; + end else + {position after the add} + ExprEdit.SelStart := position+length(add)-1; + ExprEdit.SelLength := 0; +end; + +procedure TStDlg.LParBtnClick(Sender: TObject); +begin + AddExpr('(', False); +end; + +procedure TStDlg.RParBtnClick(Sender: TObject); +begin + AddExpr(')', False); +end; + +procedure TStDlg.CommaBtnClick(Sender: TObject); +begin + AddExpr(ListSeparator, False); +end; + +procedure TStDlg.PowerBtnClick(Sender: TObject); +begin + AddExpr('^', False); +end; + +procedure TStDlg.AbsBtnClick(Sender: TObject); +begin + AddExpr('abs', True); +end; + +procedure TStDlg.ArctanBtnClick(Sender: TObject); +begin + AddExpr('arctan', True); +end; + +procedure TStDlg.CosBtnClick(Sender: TObject); +begin + AddExpr('cos', True); +end; + +procedure TStDlg.ExpBtnClick(Sender: TObject); +begin + AddExpr('exp', True); +end; + +procedure TStDlg.FracBtnClick(Sender: TObject); +begin + AddExpr('frac', True); +end; + +procedure TStDlg.IntBtnClick(Sender: TObject); +begin + AddExpr('int', True); +end; + +procedure TStDlg.LnBtnClick(Sender: TObject); +begin + AddExpr('ln', True); +end; + +procedure TStDlg.PiBtnClick(Sender: TObject); +begin + AddExpr('pi', False); +end; + +procedure TStDlg.RoundBtnClick(Sender: TObject); +begin + AddExpr('round', True); +end; + +procedure TStDlg.SinBtnClick(Sender: TObject); +begin + AddExpr('sin', True); +end; + +procedure TStDlg.SqrBtnClick(Sender: TObject); +begin + AddExpr('sqr', True); +end; + +procedure TStDlg.SqrtBtnClick(Sender: TObject); +begin + AddExpr('sqrt', True); +end; + +procedure TStDlg.Nr0BtnClick(Sender: TObject); +begin + AddExpr('0', False); +end; + +procedure TStDlg.Nr1BtnClick(Sender: TObject); +begin + AddExpr('1', False); +end; + +procedure TStDlg.Nr2BtnClick(Sender: TObject); +begin + AddExpr('2', False); +end; + +procedure TStDlg.Nr3BtnClick(Sender: TObject); +begin + AddExpr('3', False); +end; + +procedure TStDlg.Nr4BtnClick(Sender: TObject); +begin + AddExpr('4', False); +end; + +procedure TStDlg.Nr5BtnClick(Sender: TObject); +begin + AddExpr('5', False); +end; + +procedure TStDlg.Nr6BtnClick(Sender: TObject); +begin + AddExpr('6', False); +end; + +procedure TStDlg.Nr7BtnClick(Sender: TObject); +begin + AddExpr('7', False); +end; + +procedure TStDlg.Nr8BtnClick(Sender: TObject); +begin + AddExpr('8', False); +end; + +procedure TStDlg.Nr9BtnClick(Sender: TObject); +begin + AddExpr('9', False); +end; + +procedure TStDlg.DotBtnClick(Sender: TObject); +begin + AddExpr(DecimalSeparator, False); +end; + +procedure TStDlg.EBtnClick(Sender: TObject); +begin + AddExpr('E', False); +end; + +procedure TStDlg.PlusBtnClick(Sender: TObject); +begin + AddExpr('+', False); +end; + +procedure TStDlg.MinusBtnClick(Sender: TObject); +begin + AddExpr('-', False); +end; + +procedure TStDlg.MulBtnClick(Sender: TObject); +begin + AddExpr('*', False); +end; + +procedure TStDlg.DivBtnClick(Sender: TObject); +begin + AddExpr('/', False); +end; + +procedure TStDlg.EvaluateBtnClick(Sender: TObject); +var + res : double; +begin + res := ExprEdit.Evaluate; + if ExprEdit.Expr.LastError = 0 then + ResultEdit.Text := FloatToStr(res); + ExprEdit.SetFocus; +end; + +procedure TStDlg.ClearBtnClick(Sender: TObject); +begin + ExprEdit.Text := ''; + ResultEdit.Text := ''; + ExprEdit.SetFocus; +end; + +procedure TStDlg.ExprEditError(Sender: TObject; ErrorNumber: Longint; + const ErrorStr: String); +begin + ResultEdit.Text := 'Error ' + IntToStr(ErrorNumber) + ': ' + ErrorStr; +end; + +procedure TStDlg.BSBtnClick(Sender: TObject); +var + s: String; + p: Integer; +begin + s := ExprEdit.Text; + p := ExprEdit.CaretPos.X; + Delete(s, p, 1); + ExprEdit.Text := s; + ExprEdit.SetFocus; + if p = 0 then + Expredit.SelStart := 0 + else + ExprEdit.SelStart := p - 1; +end; + +end. diff --git a/components/systools/examples/financial_calculator/fincalu.lfm b/components/systools/examples/financial_calculator/fincalu.lfm new file mode 100644 index 000000000..dbb0152bd --- /dev/null +++ b/components/systools/examples/financial_calculator/fincalu.lfm @@ -0,0 +1,516 @@ +object FinCalForm: TFinCalForm + Left = 197 + Height = 674 + Top = 59 + Width = 754 + VertScrollBar.Range = 1000 + VertScrollBar.Visible = False + Caption = 'Financial Calculator' + ClientHeight = 674 + ClientWidth = 754 + Color = clBtnFace + Font.Color = clNavy + OnCreate = FormCreate + Position = poScreenCenter + LCLVersion = '1.9.0.0' + Visible = True + object Functions: TRadioGroup + Left = 8 + Height = 265 + Top = 8 + Width = 553 + AutoFill = True + Caption = 'Functions' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 3 + ClientHeight = 245 + ClientWidth = 549 + Columns = 3 + Items.Strings = ( + 'AccruedInterestMaturity' + 'AccruedInterestPeriodic' + 'BondDuration' + 'BondPrice' + 'CumulativeInterest' + 'CumulativePrincipal' + 'DecliningBalance' + 'DiscountRate' + 'DollarToDecimal' + 'DollarToDecimalText' + 'DollarToFraction' + 'DollarToFractionStr' + 'EffectiveInterestRate' + 'FutureValue' + 'FutureValueSchedule' + 'InterestRate' + 'InternalRateOfReturn' + 'IsCardValid' + 'ModifiedDuration' + 'ModifiedIRR' + 'NetPresentValue' + 'NominalInterestRate' + 'NonPeriodicIRR' + 'NonPeriodicNPV' + 'Payment' + 'PresentValue' + 'ReceivedAtMaturity' + 'RoundToDecimal' + 'TBillEquivYield' + 'TBillPrice' + 'TBillYield' + 'VariableDecliningBalance' + 'YieldPeriodic' + 'YieldDiscounted' + 'YieldMaturity' + ) + OnClick = FunctionsClick + TabOrder = 0 + TabStop = True + end + object GroupBox1: TGroupBox + Left = 8 + Height = 272 + Top = 280 + Width = 553 + Caption = 'Arguments' + ClientHeight = 252 + ClientWidth = 549 + TabOrder = 1 + object Label2: TLabel + Left = 29 + Height = 15 + Top = 48 + Width = 6 + Caption = '1' + ParentColor = False + end + object Label4: TLabel + Left = 29 + Height = 15 + Top = 80 + Width = 6 + Caption = '2' + ParentColor = False + end + object Label5: TLabel + Left = 29 + Height = 15 + Top = 112 + Width = 6 + Caption = '3' + ParentColor = False + end + object Label6: TLabel + Left = 29 + Height = 15 + Top = 144 + Width = 6 + Caption = '4' + ParentColor = False + end + object Label7: TLabel + Left = 21 + Height = 15 + Top = 216 + Width = 31 + Caption = 'String' + ParentColor = False + end + object Label3: TLabel + Left = 342 + Height = 15 + Top = 24 + Width = 24 + Caption = 'Date' + ParentColor = False + end + object Label1: TLabel + Left = 237 + Height = 15 + Top = 24 + Width = 37 + Caption = 'Integer' + ParentColor = False + end + object Label20: TLabel + Left = 109 + Height = 15 + Top = 24 + Width = 48 + Caption = 'Extended' + ParentColor = False + end + object Label10: TLabel + Left = 438 + Height = 15 + Top = 24 + Width = 75 + Caption = 'Miscellaneous' + ParentColor = False + end + object Label13: TLabel + Left = 29 + Height = 15 + Top = 176 + Width = 6 + Caption = '5' + ParentColor = False + end + object StrEdit: TEdit + Left = 69 + Height = 23 + Top = 216 + Width = 468 + Enabled = False + MaxLength = 80 + OnExit = StrEditExit + ParentShowHint = False + ShowHint = True + TabOrder = 19 + end + object E1Edit: TEdit + Tag = 1 + Left = 69 + Height = 23 + Top = 48 + Width = 130 + Enabled = False + OnExit = ExtEditExit + TabOrder = 0 + end + object E2Edit: TEdit + Tag = 2 + Left = 69 + Height = 23 + Top = 80 + Width = 130 + Enabled = False + OnExit = ExtEditExit + TabOrder = 1 + end + object E3Edit: TEdit + Tag = 3 + Left = 69 + Height = 23 + Top = 112 + Width = 130 + Enabled = False + OnExit = ExtEditExit + TabOrder = 2 + end + object E4Edit: TEdit + Tag = 4 + Left = 69 + Height = 23 + Top = 144 + Width = 130 + Color = clWhite + Enabled = False + OnExit = ExtEditExit + TabOrder = 3 + end + object I1Edit: TEdit + Tag = 1 + Left = 221 + Height = 23 + Top = 48 + Width = 73 + Enabled = False + OnExit = IntEditExit + TabOrder = 5 + end + object I2Edit: TEdit + Tag = 2 + Left = 221 + Height = 23 + Top = 80 + Width = 73 + Enabled = False + OnExit = IntEditExit + TabOrder = 6 + end + object I3Edit: TEdit + Tag = 3 + Left = 221 + Height = 23 + Top = 112 + Width = 73 + Enabled = False + OnExit = IntEditExit + TabOrder = 7 + end + object I4Edit: TEdit + Tag = 4 + Left = 221 + Height = 23 + Top = 144 + Width = 73 + Enabled = False + OnExit = IntEditExit + TabOrder = 8 + end + object D1Edit: TEdit + Tag = 1 + Left = 317 + Height = 23 + Top = 48 + Width = 73 + Color = clWhite + Enabled = False + OnExit = DateEditExit + TabOrder = 10 + end + object D2Edit: TEdit + Tag = 2 + Left = 317 + Height = 23 + Top = 80 + Width = 73 + Color = clWhite + Enabled = False + OnExit = DateEditExit + TabOrder = 11 + end + object D3Edit: TEdit + Tag = 3 + Left = 317 + Height = 23 + Top = 112 + Width = 73 + Color = clWhite + Enabled = False + OnExit = DateEditExit + TabOrder = 12 + end + object D4Edit: TEdit + Tag = 4 + Left = 317 + Height = 23 + Top = 144 + Width = 73 + Color = clWhite + Enabled = False + OnExit = DateEditExit + TabOrder = 13 + end + object FreqEdit: TComboBox + Left = 416 + Height = 23 + Top = 48 + Width = 121 + DropDownCount = 4 + ItemHeight = 15 + Items.Strings = ( + 'Annual' + 'SemiAnnual' + 'Quarterly' + 'Monthly' + ) + OnExit = FreqEditExit + Style = csDropDownList + TabOrder = 15 + end + object BasEdit: TComboBox + Left = 416 + Height = 23 + Top = 80 + Width = 121 + DropDownCount = 6 + ItemHeight = 15 + Items.Strings = ( + '30/360 NASD' + 'ACT/ACT' + 'ACT/360' + 'ACT/365' + '30/360 EUR' + '30/360 PSA' + ) + OnExit = BasEditExit + Style = csDropDownList + TabOrder = 16 + end + object TimEdit: TComboBox + Left = 416 + Height = 23 + Top = 112 + Width = 121 + DropDownCount = 2 + ItemHeight = 15 + Items.Strings = ( + 'End of Period' + 'Start of Period' + ) + OnExit = TimEditExit + Style = csDropDownList + TabOrder = 17 + end + object E5Edit: TEdit + Tag = 5 + Left = 69 + Height = 23 + Top = 176 + Width = 130 + Color = clWhite + Enabled = False + OnExit = ExtEditExit + TabOrder = 4 + end + object I5Edit: TEdit + Tag = 5 + Left = 221 + Height = 23 + Top = 176 + Width = 73 + Enabled = False + OnExit = IntEditExit + TabOrder = 9 + end + object D5Edit: TEdit + Tag = 5 + Left = 317 + Height = 23 + Top = 176 + Width = 73 + Color = clWhite + Enabled = False + OnExit = DateEditExit + TabOrder = 14 + end + object BoolEdit: TCheckBox + Left = 424 + Height = 19 + Top = 152 + Width = 75 + Caption = 'True/False' + OnExit = BoolEditExit + TabOrder = 18 + end + end + object Arrays: TGroupBox + Left = 568 + Height = 536 + Top = 8 + Width = 177 + Caption = 'Arrays' + ClientHeight = 516 + ClientWidth = 173 + TabOrder = 2 + object Label8: TLabel + Left = 68 + Height = 15 + Top = 264 + Width = 33 + Caption = 'Values' + ParentColor = False + end + object Label9: TLabel + Left = 68 + Height = 15 + Top = 24 + Width = 29 + Caption = 'Dates' + ParentColor = False + end + object VAEdit: TStringGrid + Tag = 50 + Left = 32 + Height = 215 + Top = 288 + Width = 121 + Color = clWhite + ColCount = 1 + DefaultColWidth = 118 + DefaultRowHeight = 20 + FixedCols = 0 + FixedRows = 0 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goEditing, goAlwaysShowEditor] + RowCount = 30 + ScrollBars = ssVertical + TabOrder = 1 + TitleFont.Color = clNavy + TitleFont.Height = -13 + TitleFont.Name = 'Arial' + OnEnter = VAEditEnter + OnExit = VAEditExit + end + object DAEdit: TStringGrid + Left = 32 + Height = 182 + Top = 48 + Width = 121 + Color = clWhite + ColCount = 1 + DefaultColWidth = 118 + DefaultRowHeight = 20 + FixedCols = 0 + FixedRows = 0 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goEditing, goAlwaysShowEditor] + RowCount = 30 + ScrollBars = ssVertical + TabOrder = 0 + TitleFont.Color = clNavy + TitleFont.Height = -13 + TitleFont.Name = 'Arial' + OnEnter = DAEditEnter + OnExit = DAEditExit + end + end + object Panel1: TPanel + Left = 8 + Height = 105 + Top = 560 + Width = 737 + BevelInner = bvRaised + BevelOuter = bvLowered + ClientHeight = 105 + ClientWidth = 737 + TabOrder = 3 + object GoBtn: TButton + Left = 248 + Height = 33 + Top = 60 + Width = 241 + Caption = 'Evaluate' + Default = True + OnClick = GoBtnClick + TabOrder = 2 + end + object SResult: TEdit + Left = 184 + Height = 23 + Top = 25 + Width = 529 + Color = clAqua + ReadOnly = True + TabStop = False + TabOrder = 1 + end + object BitBtn1: TBitBtn + Left = 632 + Height = 33 + Top = 60 + Width = 81 + Cancel = True + Caption = 'Close' + NumGlyphs = 2 + OnClick = BitBtn1Click + TabOrder = 3 + TabStop = False + end + object FResult: TEdit + Left = 24 + Height = 23 + Top = 24 + Width = 137 + Color = clAqua + ReadOnly = True + TabStop = False + TabOrder = 0 + end + end +end diff --git a/components/systools/examples/financial_calculator/fincalu.pas b/components/systools/examples/financial_calculator/fincalu.pas new file mode 100644 index 000000000..8902e7730 --- /dev/null +++ b/components/systools/examples/financial_calculator/fincalu.pas @@ -0,0 +1,769 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +unit Fincalu; + +interface + +uses + {$IFDEF FPC} + {$ELSE} + Windows, Messages, + {$ENDIF} + SysUtils, Controls, Classes, Forms, StdCtrls, Buttons, + ExtCtrls, Grids, Graphics, + + StFin, StDate, StDateSt; + +type + TFinCalForm = class(TForm) + Functions: TRadioGroup; + GroupBox1: TGroupBox; + Label2: TLabel; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + Label7: TLabel; + Label3: TLabel; + Label1: TLabel; + Label20: TLabel; + Arrays: TGroupBox; + Label8: TLabel; + Label9: TLabel; + StrEdit: TEdit; + Panel1: TPanel; + GoBtn: TButton; + SResult: TEdit; + BitBtn1: TBitBtn; + E1Edit: TEdit; + E2Edit: TEdit; + E3Edit: TEdit; + E4Edit: TEdit; + I1Edit: TEdit; + I2Edit: TEdit; + I3Edit: TEdit; + I4Edit: TEdit; + FResult: TEdit; + VAEdit: TStringGrid; + DAEdit: TStringGrid; + D1Edit: TEdit; + D2Edit: TEdit; + D3Edit: TEdit; + D4Edit: TEdit; + Label10: TLabel; + FreqEdit: TComboBox; + BasEdit: TComboBox; + TimEdit: TComboBox; + E5Edit: TEdit; + I5Edit: TEdit; + D5Edit: TEdit; + Label13: TLabel; + BoolEdit: TCheckBox; + + procedure SetupAccruedInterestPeriodic; + procedure SetupAccruedInterestMaturity; + procedure SetupCumulativeInterest; + procedure SetupCumulativePrincipal; + procedure SetupDiscountRate; + procedure SetupEffectiveInterestRate; + procedure SetupNominalInterestRate; + procedure SetupInterestRate; + procedure SetupReceivedAtMaturity; + procedure SetupYieldPeriodic; + procedure SetupYieldDiscounted; + procedure SetupYieldMaturity; + procedure SetupTBillEquivYield; + procedure SetupTBillPrice; + procedure SetupTBillYield; + procedure SetupBondDuration; + procedure SetupModifiedDuration; + procedure SetupFutureValueSCHEDULE; + procedure SetupModifiedIRR; + procedure SetupNonperiodicIRR; + procedure SetupNonperiodicNPV; + procedure SetupDecliningBalance; + procedure SetupVariableDecliningBalance; + procedure SetupDollarToDecimal; + procedure SetupDollarToFraction; + procedure SetupDollarToDecimalText; + procedure SetupDollarToFractionStr; + procedure SetupRoundToDecimal; + procedure SetupIsCardValid; + procedure SetupNetPresentValue; + procedure SetupFutureValue; + procedure SetupPresentValue; + procedure SetupBondPrice; + procedure SetupPayment; + procedure SetupInternalRateOfReturn; + procedure ExtEditExit(Sender: TObject); + procedure IntEditExit(Sender: TObject); + procedure DisableFields; + procedure FunctionsClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure GoBtnClick(Sender: TObject); + procedure FT(F : TWinControl; T: Integer; S: string); + procedure DateEditExit(Sender: TObject); + procedure VAEditExit(Sender: TObject); + procedure DAEditExit(Sender: TObject); + procedure FreqEditExit(Sender: TObject); + procedure BasEditExit(Sender: TObject); + procedure TimEditExit(Sender: TObject); + procedure StrEditExit(Sender: TObject); + procedure VAEditEnter(Sender: TObject); + procedure DAEditEnter(Sender: TObject); + procedure BoolEditExit(Sender: TObject); + procedure BitBtn1Click(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + FinCalForm: TFinCalForm; + +implementation + +{$R *.lfm} + +var + ExtVar : array[1..5] of Extended; + IntVar : array[1..5] of Integer; + DateVar : array[1..5] of TStDate; + FreqVar : TStFrequency; + BasVar : TStBasis; + TimVar : TStPaymentTime; + StrVar : String; + BoolVar : Boolean; + DateArray : array[0..29] of TStDate; + ValArray : array[0..29] of Double; + + +{------ Function parameters ------} + +procedure TFinCalForm.FT(F : TWinControl; T: Integer; S: string); +begin + F.Enabled := true; + TEdit(F).Color := clYellow; + F.TabOrder := T; + F.Hint := S; + F.ShowHint := true; +end; + +procedure TFinCalForm.SetupAccruedInterestPeriodic; +begin + FT(D1Edit, 1, 'Issue'); + FT(D2Edit, 2, 'Settlement'); + FT(D3Edit, 3, 'Maturity'); + FT(E1Edit, 4, 'Rate'); + FT(E2Edit, 5, 'Par'); + FT(FreqEdit, 6, 'Frequency'); + FT(BasEdit, 7, 'Basis'); +end; + +procedure TFinCalForm.SetupAccruedInterestMaturity; +begin + FT(D1Edit, 1, 'Issue'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Rate'); + FT(E2Edit, 4, 'Par'); + FT(BasEdit, 5, 'Basis'); +end; + +procedure TFinCalForm.SetupCumulativeInterest; +begin + FT(E1Edit, 1, 'Rate'); + FT(I1Edit, 2, 'NPeriods'); + FT(E2Edit, 3, 'Present Value'); + FT(I2Edit, 4, 'Start Period'); + FT(I3Edit, 5, 'End Period'); + FT(FreqEdit, 6, 'Frequency'); + FT(TimEdit, 7, 'Timing'); +end; + +procedure TFinCalForm.SetupCumulativePrincipal; +begin + SetupCumulativeInterest; +end; + +procedure TFinCalForm.SetupDiscountRate; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Price'); + FT(E2Edit, 4, 'Redemption'); + FT(BasEdit, 5, 'Basis'); +end; + +procedure TFinCalForm.SetupEffectiveInterestRate; +begin + FT(E1Edit, 1, 'Nominal Rate'); + FT(FreqEdit, 2, 'Frequency'); +end; + +procedure TFinCalForm.SetupNominalInterestRate; +begin + FT(E1Edit, 1, 'Effective Rate'); + FT(FreqEdit, 2, 'Frequency'); +end; + +procedure TFinCalForm.SetupInterestRate; +begin + FT(I1Edit, 1, 'NPeriods'); + FT(E1Edit, 2, 'Payment'); + FT(E2Edit, 3, 'Present Value'); + FT(E3Edit, 4, 'Future Value'); + FT(FreqEdit, 5, 'Frequency'); + FT(TimEdit, 6, 'Timing'); + FT(E4Edit, 7, 'Guess'); +end; + +procedure TFinCalForm.SetupReceivedAtMaturity; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Investment'); + FT(E2Edit, 4, 'Discount'); + FT(BasEdit, 5, 'Basis'); +end; + +procedure TFinCalForm.SetupYieldPeriodic; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Rate'); + FT(E2Edit, 4, 'Price'); + FT(E3Edit, 5, 'Redemption'); + FT(FreqEdit, 6, 'Frequency'); + FT(BasEdit, 7, 'Basis'); +end; + +procedure TFinCalForm.SetupYieldDiscounted; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Price'); + FT(E2Edit, 4, 'Redemption'); + FT(BasEdit, 5, 'Basis'); +end; + +procedure TFinCalForm.SetupYieldMaturity; +begin + FT(D1Edit, 1, 'Issue'); + FT(D2Edit, 2, 'Settlement'); + FT(D3Edit, 3, 'Maturity'); + FT(E1Edit, 4, 'Rate'); + FT(E2Edit, 5, 'Price'); + FT(BasEdit, 6, 'Basis'); +end; + +procedure TFinCalForm.SetupTBillEquivYield; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Discount'); +end; + +procedure TFinCalForm.SetupTBillPrice; +begin + SetupTBillEquivYield; +end; + +procedure TFinCalForm.SetupTBillYield; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Price'); +end; + +procedure TFinCalForm.SetupBondDuration; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Rate'); + FT(E2Edit, 4, 'Yield'); + FT(FreqEdit, 5, 'Frequency'); + FT(BasEdit, 6, 'Basis'); +end; + +procedure TFinCalForm.SetupModifiedDuration; +begin + SetupBondDuration; +end; + +procedure TFinCalForm.SetupFutureValueSCHEDULE; +begin + FT(E1Edit, 1, 'Principal'); + FT(VAEdit, 2, 'Schedule'); + FT(I1Edit, 3, 'NRates'); +end; + +procedure TFinCalForm.SetupModifiedIRR; +begin + FT(VAEdit, 1, 'Values'); + FT(I1Edit, 2, 'NValues'); + FT(E1Edit, 3, 'Finance Rate'); + FT(E2Edit, 4, 'Reinvest Rate'); +end; + +procedure TFinCalForm.SetupNonperiodicIRR; +begin + FT(I1Edit, 1, 'NValues'); + FT(VAEdit, 2, 'Values'); + FT(DAEdit, 3, 'Dates'); + FT(E1Edit, 4, 'Guess'); +end; + +procedure TFinCalForm.SetupNonperiodicNPV; +begin + FT(I1Edit, 1, 'NValues'); + FT(E1Edit, 2, 'Rate'); + FT(VAEdit, 3, 'Values'); + FT(DAEdit, 4, 'Dates'); +end; + +procedure TFinCalForm.SetupDecliningBalance; +begin + FT(E1Edit, 1, 'Cost'); + FT(E2Edit, 2, 'Salvage'); + FT(I1Edit, 3, 'Life'); + FT(I2Edit, 4, 'Period'); + FT(I3Edit, 5, 'Month'); +end; + +procedure TFinCalForm.SetupVariableDecliningBalance; +begin + FT(E1Edit, 1, 'Cost'); + FT(E2Edit, 2, 'Salvage'); + FT(I1Edit, 3, 'Life'); + FT(E3Edit, 4, 'Start'); + FT(E4Edit, 5, 'End'); + FT(E5Edit, 6, 'Factor'); + FT(BoolEdit, 7, 'No Switch'); +end; + +procedure TFinCalForm.SetupDollarToDecimal; +begin + FT(E1Edit, 1, 'Fractional Dollar'); + FT(I1Edit, 2, 'Fraction'); +end; + +procedure TFinCalForm.SetupDollarToFraction; +begin + FT(E1Edit, 1, 'Decimal Dollar'); + FT(I1Edit, 2, 'Fraction'); +end; + +procedure TFinCalForm.SetupDollarToDecimalText; +begin + FT(E1Edit, 1, 'Decimal Dollar'); +end; + +procedure TFinCalForm.SetupDollarToFractionStr; +begin + FT(E1Edit, 1, 'Fractional Dollar'); + FT(I1Edit, 2, 'Fraction'); +end; + +procedure TFinCalForm.SetupRoundToDecimal; +begin + FT(E1Edit, 1, 'Value'); + FT(I1Edit, 2, 'Places'); + FT(BoolEdit, 3, 'Bankers'); +end; + +procedure TFinCalForm.SetupIsCardValid; +begin + FT(StrEdit, 1, 'Card Number'); +end; + +procedure TFinCalForm.SetupNetPresentValue; +begin + FT(E1Edit, 1, 'Rate'); + FT(I1Edit, 2, 'NValues'); + FT(VAEdit, 3, 'Values'); +end; + +procedure TFinCalForm.SetupFutureValue; +begin + FT(E1Edit, 1, 'Rate'); + FT(I1Edit, 2, 'NPeriods'); + FT(E2Edit, 3, 'Payment'); + FT(E3Edit, 4, 'Present Value'); + FT(FreqEdit, 5, 'Frequency'); + FT(TimEdit, 6, 'Timing'); +end; + +procedure TFinCalForm.SetupPresentValue; +begin + FT(E1Edit, 1, 'Rate'); + FT(I1Edit, 2, 'NPeriods'); + FT(E2Edit, 3, 'Payment'); + FT(E3Edit, 4, 'Future Value'); + FT(FreqEdit, 5, 'Frequency'); + FT(TimEdit, 6, 'Timing'); +end; + +procedure TFinCalForm.SetupBondPrice; +begin + FT(D1Edit, 1, 'Settlement'); + FT(D2Edit, 2, 'Maturity'); + FT(E1Edit, 3, 'Rate'); + FT(E2Edit, 4, 'Yield'); + FT(E3Edit, 5, 'Redemption'); + FT(FreqEdit, 6, 'Frequency'); + FT(BasEdit, 7, 'Basis'); +end; + +procedure TFinCalForm.SetupPayment; +begin + FT(E1Edit, 1, 'Rate'); + FT(I1Edit, 2, 'NPeriods'); + FT(E2Edit, 3, 'Present Value'); + FT(E3Edit, 4, 'Future Value'); + FT(FreqEdit, 5, 'Frequency'); + FT(TimEdit, 6, 'Timing'); +end; + +procedure TFinCalForm.SetupInternalRateOfReturn; +begin + FT(I1Edit, 1, 'NValues'); + FT(VAEdit, 2, 'Values'); + FT(E1Edit, 3, 'Guess'); +end; + + + +{------- Function selection -------} + +procedure TFinCalForm.GoBtnClick(Sender: TObject); +var + FR : Extended; + SR : String; +begin + FR := 0; + SR := ''; + case Functions.ItemIndex of + 0 : FR := AccruedInterestMaturity(DateVar[1], DateVar[2], ExtVar[1], + ExtVar[2], BasVar); + 1 : FR := AccruedInterestPeriodic(DateVar[1], DateVar[2], DateVar[3], + ExtVar[1], ExtVar[2], FreqVar, BasVar); + 2 : FR := BondDuration(DateVar[1], DateVar[2], ExtVar[1], ExtVar[2], + FreqVar, BasVar); + 3 : FR := BondPrice(DateVar[1], DateVar[2], ExtVar[1], ExtVar[2], + ExtVar[3], FreqVar, BasVar); + 4 : FR := CumulativeInterest(ExtVar[1], IntVar[1], ExtVar[2], IntVar[2], + IntVar[3], FreqVar, TimVar); + 5 : FR := CumulativePrincipal(ExtVar[1], IntVar[1], ExtVar[2], IntVar[2], + IntVar[3], FreqVar, TimVar); + 6 : FR := DecliningBalance(ExtVar[1], ExtVar[2], IntVar[1], IntVar[2], + IntVar[3]); + 7 : FR := DiscountRate(DateVar[1], DateVar[2], ExtVar[1], ExtVar[2], + BasVar); + 8 : FR := DollarToDecimal(ExtVar[1], IntVar[1]); + + 9 : SR := DollarToDecimalText(ExtVar[1]); + + 10 : FR := DollarToFraction(ExtVar[1], IntVar[1]); + + 11 : SR := DollarToFractionStr(ExtVar[1], IntVar[1]); + + 12 : FR := EffectiveInterestRate(ExtVar[1], FreqVar); + + 13 : FR := FutureValue(ExtVar[1], IntVar[1], ExtVar[2], ExtVar[3], + FreqVar, TimVar); + 14 : FR := FutureValueSchedule16(ExtVar[1], ValArray, IntVar[1]); + + 15 : FR := InterestRate(IntVar[1], ExtVar[1], ExtVar[2], ExtVar[3], + FreqVar, TimVar, ExtVar[4]); + 16 : FR := InternalRateOfReturn16(ValArray, IntVar[1], ExtVar[1]); + + 17 : if IsCardValid(StrVar) then + SR := 'Valid card number' + else + SR := 'Invalid card number'; + 18 : FR := ModifiedDuration(DateVar[1], DateVar[2], ExtVar[1], + ExtVar[2], FreqVar, BasVar); + 19 : FR := ModifiedIRR16(ValArray, IntVar[1], ExtVar[1], ExtVar[2]); + + 20 : FR := NetPresentValue16(ExtVar[1], ValArray, IntVar[1]); + + 21 : FR := NominalInterestRate(ExtVar[1], FreqVar); + + 22 : FR := NonPeriodicIRR16(ValArray, DateArray, IntVar[1], ExtVar[1]); + + 23 : FR := NonPeriodicNPV16(ExtVar[1], ValArray, DateArray, IntVar[1]); + + 24 : FR := Payment(ExtVar[1], IntVar[1], ExtVar[2], ExtVar[3], + FreqVar, TimVar); + 25 : FR := PresentValue(ExtVar[1], IntVar[1], ExtVar[2], ExtVar[3], + FreqVar, TimVar); + 26 : FR := ReceivedAtMaturity(DateVar[1], DateVar[2], ExtVar[1], + ExtVar[2], BasVar); + 27 : FR := RoundToDecimal(ExtVar[1], IntVar[1], BoolVar); + + 28 : FR := TBillEquivYield(DateVar[1], DateVar[2], ExtVar[1]); + + 29 : FR := TBillPrice(DateVar[1], DateVar[2], ExtVar[1]); + + 30 : FR := TBillYield(DateVar[1], DateVar[2], ExtVar[1]); + + 31 : FR := VariableDecliningBalance(ExtVar[1], ExtVar[2], IntVar[1], + ExtVar[3], ExtVar[4], ExtVar[5], BoolVar); + 32 : FR := YieldPeriodic(DateVar[1], DateVar[2], ExtVar[1], ExtVar[2], + ExtVar[3], FreqVar, BasVar); + 33 : FR := YieldDiscounted(DateVar[1], DateVar[2], ExtVar[1], + ExtVar[2], BasVar); + 34 : FR := YieldMaturity(DateVar[1], DateVar[2], DateVar[3], ExtVar[1], + ExtVar[2], BasVar); + end; + FResult.Text := FloatToStr(FR); + SResult.Text := SR; +end; + +procedure TFinCalForm.FunctionsClick(Sender: TObject); +begin + DisableFields; + case Functions.ItemIndex of + 0 : SetupAccruedInterestMaturity; + 1 : SetupAccruedInterestPeriodic; + 2 : SetupBondDuration; + 3 : SetupBondPrice; + 4 : SetupCumulativeInterest; + 5 : SetupCumulativePrincipal; + 6 : SetupDecliningBalance; + 7 : SetupDiscountRate; + 8 : SetupDollarToDecimal; + 9 : SetupDollarToDecimalText; + 10 : SetupDollarToFraction; + 11 : SetupDollarToFractionStr; + 12 : SetupEffectiveInterestRate; + 13 : SetupFutureValue; + 14 : SetupFutureValueSchedule; + 15 : SetupInterestRate; + 16 : SetupInternalRateOfReturn; + 17 : SetupIsCardValid; + 18 : SetupModifiedDuration; + 19 : SetupModifiedIRR; + 20 : SetupNetPresentValue; + 21 : SetupNominalInterestRate; + 22 : SetupNonperiodicIRR; + 23 : SetupNonperiodicNPV; + 24 : SetupPayment; + 25 : SetupPresentValue; + 26 : SetupReceivedAtMaturity; + 27 : SetupRoundToDecimal; + 28 : SetupTBillEquivYield; + 29 : SetupTBillPrice; + 30 : SetupTBillYield; + 31 : SetupVariableDecliningBalance; + 32 : SetupYieldPeriodic; + 33 : SetupYieldDiscounted; + 34 : SetupYieldMaturity; + end; +end; + +{------- Misc utilities and set up -------} + +procedure TFinCalForm.DisableFields; +begin + E1Edit.Enabled := false; + E1Edit.Color := clwhite; + E2Edit.Enabled := false; + E2Edit.Color := clwhite; + E3Edit.Enabled := false; + E3Edit.Color := clwhite; + E4Edit.Enabled := false; + E4Edit.Color := clwhite; + E5Edit.Enabled := false; + E5Edit.Color := clwhite; + I1Edit.Enabled := false; + I1Edit.Color := clwhite; + I2Edit.Enabled := false; + I2Edit.Color := clwhite; + I3Edit.Enabled := false; + I3Edit.Color := clwhite; + I4Edit.Enabled := false; + I4Edit.Color := clwhite; + I5Edit.Enabled := false; + I5Edit.Color := clwhite; + D1Edit.Enabled := false; + D1Edit.Color := clwhite; + D2Edit.Enabled := false; + D2Edit.Color := clwhite; + D3Edit.Enabled := false; + D3Edit.Color := clwhite; + D4Edit.Enabled := false; + D4Edit.Color := clwhite; + D5Edit.Enabled := false; + D5Edit.Color := clwhite; + DAEdit.Enabled := false; + DAEdit.Color := clwhite; + VAEdit.Enabled := false; + VAEdit.Color := clwhite; + StrEdit.Enabled := false; + StrEdit.Color := clwhite; + TimEdit.Enabled := False; + TimEdit.Color := clWhite; + BasEdit.Enabled := False; + BasEdit.Color := clWhite; + FreqEdit.Enabled := False; + FreqEdit.Color := clWhite; + BoolEdit.Enabled := false; + BoolEdit.Color := clWhite; +end; + +procedure TFinCalForm.ExtEditExit(Sender: TObject); +begin + with (Sender as TEdit) do + ExtVar[Tag] := StrToFloat(Text); +end; + +procedure TFinCalForm.IntEditExit(Sender: TObject); +begin + with (Sender as TEdit) do + IntVar[Tag] := StrToInt(Text); +end; + +procedure TFinCalForm.DateEditExit(Sender: TObject); +begin + with (Sender as TEdit) do + DateVar[Tag] := DateStringToStDate('mm/dd/yy', Text, 1920); +end; + +procedure TFinCalForm.StrEditExit(Sender: TObject); +begin + StrVar := TEdit(Sender).Text; +end; + +procedure TFinCalForm.DAEditEnter(Sender: TObject); +begin + DAEdit.Row := 0; + DAEdit.Col := 0; +end; + +procedure TFinCalForm.DAEditExit(Sender: TObject); +var + I : Integer; +begin + for I := 0 to IntVar[1] - 1 do + DateArray[I] := DateStringToStDate('mm/dd/yy', DAEdit.Cells[0,I], 1950); +end; + +procedure TFinCalForm.VAEditEnter(Sender: TObject); +begin + VAEdit.Row := 0; + VAEdit.Col := 0; +end; + +procedure TFinCalForm.VAEditExit(Sender: TObject); +var + I : Integer; +begin + for I := 0 to IntVar[1] - 1 do + ValArray[I] := StrToFloat(VAEdit.Cells[0,I]); +end; + +procedure TFinCalForm.FreqEditExit(Sender: TObject); +begin + case FreqEdit.ItemIndex of + 0: FreqVar := fqAnnual; + 1: FreqVar := fqSemiAnnual; + 2: FreqVar := fqQuarterly; + 3: FreqVar := fqMonthly; + end; +end; + +procedure TFinCalForm.BasEditExit(Sender: TObject); +begin + case BasEdit.ItemIndex of + 0: BasVar := BasisNASD; + 1: BasVar := BasisActAct; + 2: BasVar := BasisAct360; + 3: BasVar := BasisAct365; + 4: BasVar := BasisEur30360; + end; +end; + +procedure TFinCalForm.TimEditExit(Sender: TObject); +begin + case TimEdit.ItemIndex of + 0: TimVar := ptEndOfPeriod; + 1: TimVar := ptStartOfPeriod; + end; +end; + +procedure TFinCalForm.BoolEditExit(Sender: TObject); +begin + BoolVar := BoolEdit.Checked; +end; + +procedure TFinCalForm.FormCreate(Sender: TObject); +var + I : Integer; +begin + for I := 1 to 5 do begin + ExtVar[I] := 0; + DateVar[I] := CurrentDate; + IntVar[I] := 0; + end; + E1Edit.Text := FloatToStr(ExtVar[1]); + E2Edit.Text := FloatToStr(ExtVar[2]); + E3Edit.Text := FloatToStr(ExtVar[3]); + E4Edit.Text := FloatToStr(ExtVar[4]); + E5Edit.Text := FloatToStr(ExtVar[5]); + I1Edit.Text := IntToStr(IntVar[1]); + I2Edit.Text := IntToStr(IntVar[2]); + I3Edit.Text := IntToStr(IntVar[3]); + I4Edit.Text := IntToStr(IntVar[4]); + I5Edit.Text := IntToStr(IntVar[5]); + D1Edit.Text := DateToStr(DateVar[1]); + D2Edit.Text := DateToStr(DateVar[2]); + D3Edit.Text := DateToStr(DateVar[3]); + D4Edit.Text := DateToStr(DateVar[4]); + D5Edit.Text := DateToStr(DateVar[5]); + DisableFields; + for I := 0 to 29 do begin + ValArray[I] := 0; + DateArray[I] := CurrentDate; + end; + TimEdit.ItemIndex := 0; + TimVar := ptEndOfPeriod; + BasEdit.ItemIndex := 0; + BasVar := BasisNASD; + FreqEdit.ItemIndex := 0; + FreqVar := fqAnnual; + BoolEdit.Checked := false; + BoolVar := false; + Application.HintPause := 250; + Application.HintColor := clAqua; +end; + +procedure TFinCalForm.BitBtn1Click(Sender: TObject); +begin + Close; +end; + +end. diff --git a/components/systools/examples/financial_calculator/fincl.lpi b/components/systools/examples/financial_calculator/fincl.lpi new file mode 100644 index 000000000..15894a734 --- /dev/null +++ b/components/systools/examples/financial_calculator/fincl.lpi @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <General> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="fincl"/> + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="laz_systools"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="2"> + <Unit0> + <Filename Value="fincl.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Fincal"/> + </Unit0> + <Unit1> + <Filename Value="fincalu.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FinCalForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Fincalu"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="fincl"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/systools/examples/financial_calculator/fincl.lpr b/components/systools/examples/financial_calculator/fincl.lpr new file mode 100644 index 000000000..af6d62f1e --- /dev/null +++ b/components/systools/examples/financial_calculator/fincl.lpr @@ -0,0 +1,42 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +program Fincal; + +uses + Interfaces, + Forms, lclversion, + fincalu in 'fincalu.pas' {FinCalForm}; + +{$R *.res} + +begin + {$IF lcl_fullversion >= 1080000} + Application.Scaled := True; + {$ENDIF} + Application.Initialize; + Application.CreateForm(TFinCalForm, FinCalForm); + Application.Run; +end. diff --git a/components/systools/examples/html/ex2html.lpi b/components/systools/examples/html/ex2html.lpi new file mode 100644 index 000000000..f61762f21 --- /dev/null +++ b/components/systools/examples/html/ex2html.lpi @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <General> + <Flags> + <UseDefaultCompilerOptions Value="True"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="ex2html"/> + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="laz_systools"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="2"> + <Unit0> + <Filename Value="ex2html.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="EX2HTML"/> + </Unit0> + <Unit1> + <Filename Value="ex2htmlu.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="ex2html"/> + </Target> + <SearchPaths> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/systools/examples/html/ex2html.lpr b/components/systools/examples/html/ex2html.lpr new file mode 100644 index 000000000..ce1f88c06 --- /dev/null +++ b/components/systools/examples/html/ex2html.lpr @@ -0,0 +1,38 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +program EX2HTML; + +uses + Forms, Interfaces, + ex2htmlu in 'ex2htmlu.pas' {Form1}; + +{$R *.RES} + +begin + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. diff --git a/components/systools/examples/html/ex2htmlu.lfm b/components/systools/examples/html/ex2htmlu.lfm new file mode 100644 index 000000000..0db667245 --- /dev/null +++ b/components/systools/examples/html/ex2htmlu.lfm @@ -0,0 +1,184 @@ +object Form1: TForm1 + Left = 384 + Height = 184 + Top = 318 + Width = 221 + BorderStyle = bsDialog + Caption = 'EXTOHTML' + ClientHeight = 184 + ClientWidth = 221 + Color = clBtnFace + Font.Color = clBlack + Position = poScreenCenter + LCLVersion = '1.9.0.0' + object Label1: TLabel + Left = 10 + Height = 15 + Top = 12 + Width = 49 + Caption = 'Input File' + ParentColor = False + end + object Label2: TLabel + Left = 10 + Height = 15 + Top = 59 + Width = 59 + Caption = 'Output File' + ParentColor = False + end + object SpeedButton1: TSpeedButton + Left = 184 + Height = 25 + Top = 28 + Width = 25 + OnClick = GetFileClick + end + object SpeedButton2: TSpeedButton + Left = 183 + Height = 25 + Top = 75 + Width = 25 + OnClick = GetFileClick + end + object Label3: TLabel + Left = 10 + Height = 15 + Top = 115 + Width = 41 + Caption = 'Waiting' + ParentColor = False + end + object Button1: TButton + Left = 66 + Height = 25 + Top = 147 + Width = 75 + Caption = 'Convert' + OnClick = Button1Click + TabOrder = 2 + end + object Edit1: TEdit + Left = 10 + Height = 23 + Top = 29 + Width = 169 + TabOrder = 0 + Text = '..\..\source\run/sttohtml.pas' + end + object Edit2: TEdit + Left = 10 + Height = 23 + Top = 76 + Width = 168 + TabOrder = 1 + Text = 'out.htm' + end + object StFileToHTML1: TStFileToHTML + CommentMarkers.Strings = ( + '//=;<font color=#FF0000><i>;</i></font>' + '(*=*);<font color=#FF0000><i>;</i></font>' + '/*=*/;<font color=#FF0000><i>;</i></font>' + '{=};<font color=#FF0000><i>;</i></font>' + ) + EmbeddedHTML.Strings = ( + '"="' + '&=&' + '<=<' + '>=>' + '¡=¡' + '¢=¢' + '£=£' + '©=©' + '®=®' + '±=±' + '¼=¼' + '½=½' + '¾=¾' + '÷=÷' + ) + Keywords.Strings = ( + 'and=<B>;</B>' + 'array=<B>;</B>' + 'as=<B>;</B>' + 'asm=<B>;</B>' + 'begin=<B>;</B>' + 'case=<B>;</B>' + 'class=<B>;</B>' + 'const=<B>;</B>' + 'constructor=<B>;</B>' + 'destructor=<B>;</B>' + 'dispinterface=<B>;</B>' + 'div=<B>;</B>' + 'do=<B>;</B>' + 'downto=<B>;</B>' + 'else=<B>;</B>' + 'end=<B>;</B>' + 'except=<B>;</B>' + 'exports=<B>;</B>' + 'file=<B>;</B>' + 'finalization=<B>;</B>' + 'finally=<B>;</B>' + 'for=<B>;</B>' + 'function=<B>;</B>' + 'goto=<B>;</B>' + 'if=<B>;</B>' + 'implementation=<B>;</B>' + 'in=<B>;</B>' + 'inherited=<B>;</B>' + 'initialization=<B>;</B>' + 'inline=<B>;</B>' + 'interface=<B>;</B>' + 'is=<B>;</B>' + 'label=<B>;</B>' + 'library=<B>;</B>' + 'mod=<B>;</B>' + 'nil=<B>;</B>' + 'not=<B>;</B>' + 'object=<B>;</B>' + 'of=<B>;</B>' + 'or=<B>;</B>' + 'out=<B>;</B>' + 'packed=<B>;</B>' + 'procedure=<B>;</B>' + 'program=<B>;</B>' + 'property=<B>;</B>' + 'protected=<B>;</B>' + 'public=<B>;</B>' + 'raise=<B>;</B>' + 'record=<B>;</B>' + 'repeat=<B>;</B>' + 'resourcestring=<B>;</B>' + 'set=<B>;</B>' + 'shl=<B>;</B>' + 'shr=<B>;</B>' + 'string=<B>;</B>' + 'then=<B>;</B>' + 'thread=<B>;</B>' + 'var=<B>;</B>' + 'to=<B>;</B>' + 'try=<B>;</B>' + 'type=<B>;</B>' + 'unit=<B>;</B>' + 'until=<B>;</B>' + 'uses=<B>;</B>' + 'var=<B>;</B>' + 'while=<B>;</B>' + 'with=<B>;</B>' + ) + OnProgress = StFileToHTML1Progress + StringMarkers.Strings = ( + '"=";<font color=#0000FF>;</font>' + '''='';<font color=#0000FF>;</font>' + ) + WordDelimiters = ',; .()' + left = 133 + top = 1 + end + object OpenDialog1: TOpenDialog + Filter = 'Pascal files (*.pas)|*.pas|C++ files (*.cpp)|*.cpp|All files (*.*)|*.*' + Options = [ofOverwritePrompt, ofPathMustExist] + left = 97 + top = 65535 + end +end diff --git a/components/systools/examples/html/ex2htmlu.pas b/components/systools/examples/html/ex2htmlu.pas new file mode 100644 index 000000000..29633a06d --- /dev/null +++ b/components/systools/examples/html/ex2htmlu.pas @@ -0,0 +1,99 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +unit ex2htmlu; + +interface + +uses + {$IFNDEF FPC} + Windows, Messages, + {$ENDIF} + SysUtils, Classes, Graphics, Controls, + Forms, Dialogs, StdCtrls, Buttons, + + StBase, StToHTML; + +type + TForm1 = class(TForm) + Button1: TButton; + StFileToHTML1: TStFileToHTML; + Edit1: TEdit; + Edit2: TEdit; + Label1: TLabel; + Label2: TLabel; + SpeedButton1: TSpeedButton; + SpeedButton2: TSpeedButton; + Label3: TLabel; + OpenDialog1: TOpenDialog; + procedure Button1Click(Sender: TObject); + procedure GetFileClick(Sender: TObject); + procedure StFileToHTML1Progress(Sender: TObject; Percent: Word); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form1: TForm1; + +implementation + +{$R *.lfm} + +procedure TForm1.Button1Click(Sender: TObject); +begin + if (not FileExists(Edit1.Text)) then begin + ShowMessage('Input file does not exist'); + Exit; + end; + + StFileToHTML1.InFileName := Edit1.Text; + StFileToHTML1.OutFileName := Edit2.Text; + + StFileToHTML1.Execute; + Label1.Caption := 'Waiting'; + ShowMessage('Done'); +end; + + +procedure TForm1.GetFileClick(Sender: TObject); +begin + if (OpenDialog1.Execute) then begin + if (Sender = SpeedButton1) then + Edit1.Text := OpenDialog1.FileName + else if (Sender = SpeedButton2) then + Edit2.Text := OpenDialog1.FileName; + end; +end; + +procedure TForm1.StFileToHTML1Progress(Sender: TObject; Percent: Word); +begin + Label1.Caption := 'Completed: ' + IntToStr(Percent) + '%'; +end; + + +end. diff --git a/components/systools/examples/money_calculator/moneycal0.lfm b/components/systools/examples/money_calculator/moneycal0.lfm new file mode 100644 index 000000000..2dea38507 --- /dev/null +++ b/components/systools/examples/money_calculator/moneycal0.lfm @@ -0,0 +1,369 @@ +object MoneyCalcDlg: TMoneyCalcDlg + Left = 191 + Height = 283 + Top = 116 + Width = 756 + BorderStyle = bsDialog + Caption = 'Money Calculator' + ClientHeight = 283 + ClientWidth = 756 + Color = clBtnFace + Font.Color = clWindowText + OnCreate = FormCreate + OnDestroy = FormDestroy + OnKeyPress = FormKeyPress + LCLVersion = '1.9.0.0' + object GroupBox1: TGroupBox + Left = 4 + Height = 268 + Top = 4 + Width = 209 + Caption = ' Calculator ' + ClientHeight = 248 + ClientWidth = 205 + TabOrder = 0 + TabStop = True + object ZeroBtn: TBitBtn + Left = 8 + Height = 28 + Top = 214 + Width = 35 + Caption = '0' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 1 + TabStop = False + end + object DecKey: TBitBtn + Left = 86 + Height = 28 + Top = 214 + Width = 35 + Caption = '.' + Font.Color = clBlue + OnClick = DecKeyClick + ParentFont = False + TabOrder = 4 + TabStop = False + end + object ThreeKey: TBitBtn + Tag = 3 + Left = 86 + Height = 28 + Top = 181 + Width = 35 + Caption = '3' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 7 + TabStop = False + end + object OneKey: TBitBtn + Tag = 1 + Left = 8 + Height = 28 + Top = 181 + Width = 35 + Caption = '1' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 2 + TabStop = False + end + object TwoKey: TBitBtn + Tag = 2 + Left = 47 + Height = 28 + Top = 181 + Width = 35 + Caption = '2' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 3 + TabStop = False + end + object SixKey: TBitBtn + Tag = 6 + Left = 86 + Height = 28 + Top = 149 + Width = 35 + Caption = '6' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 10 + TabStop = False + end + object FourKey: TBitBtn + Tag = 4 + Left = 8 + Height = 28 + Top = 149 + Width = 35 + Caption = '4' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 5 + TabStop = False + end + object FiveKey: TBitBtn + Tag = 5 + Left = 47 + Height = 28 + Top = 149 + Width = 35 + Caption = '5' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 6 + TabStop = False + end + object NineKey: TBitBtn + Tag = 9 + Left = 86 + Height = 28 + Top = 116 + Width = 35 + Caption = '9' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 16 + TabStop = False + end + object SevenKey: TBitBtn + Tag = 7 + Left = 8 + Height = 28 + Top = 116 + Width = 35 + Caption = '7' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 8 + TabStop = False + end + object EightKey: TBitBtn + Tag = 8 + Left = 47 + Height = 28 + Top = 116 + Width = 35 + Caption = '8' + Font.Color = clBlue + OnClick = NumBtnClick + ParentFont = False + TabOrder = 9 + TabStop = False + end + object AddBtn: TBitBtn + Left = 125 + Height = 28 + Top = 214 + Width = 35 + Caption = '+' + Font.Color = clRed + OnClick = AddBtnClick + ParentFont = False + TabOrder = 12 + TabStop = False + end + object SubBtn: TBitBtn + Left = 125 + Height = 28 + Top = 181 + Width = 35 + Caption = '-' + Font.Color = clRed + OnClick = SubBtnClick + ParentFont = False + TabOrder = 13 + TabStop = False + end + object MulBtn: TBitBtn + Left = 125 + Height = 28 + Top = 149 + Width = 35 + Caption = '*' + Font.Color = clRed + OnClick = MulBtnClick + ParentFont = False + TabOrder = 14 + TabStop = False + end + object DivBtn: TBitBtn + Left = 125 + Height = 28 + Top = 116 + Width = 35 + Caption = '/' + Font.Color = clRed + OnClick = DivBtnClick + ParentFont = False + TabOrder = 15 + TabStop = False + end + object PlusMinusBtn: TBitBtn + Left = 47 + Height = 28 + Top = 214 + Width = 35 + Caption = '+/-' + Font.Color = clBlue + OnClick = PlusMinusBtnClick + ParentFont = False + TabOrder = 11 + TabStop = False + end + object ClearBtn: TBitBtn + Left = 147 + Height = 28 + Top = 80 + Width = 52 + Caption = 'C' + Font.Color = clRed + OnClick = ClearBtnClick + ParentFont = False + TabOrder = 19 + TabStop = False + end + object EqualBtn: TBitBtn + Left = 164 + Height = 126 + Top = 116 + Width = 35 + Caption = '=' + Font.Color = clRed + OnClick = EqualBtnClick + ParentFont = False + TabOrder = 0 + TabStop = False + end + object ClearEntryBtn: TBitBtn + Left = 86 + Height = 28 + Top = 80 + Width = 56 + Caption = 'CE' + Font.Color = clRed + OnClick = ClearEntryBtnClick + ParentFont = False + TabOrder = 18 + TabStop = False + end + object Memo1: TMemo + Left = 8 + Height = 73 + Top = 0 + Width = 191 + Alignment = taRightJustify + MaxLength = 40 + OnKeyDown = Memo1KeyDown + PopupMenu = PopupMenu1 + ReadOnly = True + TabOrder = 20 + WantReturns = False + WantTabs = True + WordWrap = False + end + object BSBtn: TBitBtn + Left = 8 + Height = 28 + Top = 80 + Width = 74 + Caption = 'Backspace' + Font.Color = clRed + OnClick = BSBtnClick + ParentFont = False + TabOrder = 17 + TabStop = False + end + end + object GroupBox2: TGroupBox + Left = 220 + Height = 268 + Top = 4 + Width = 524 + Caption = ' Conversions ' + ClientHeight = 248 + ClientWidth = 520 + TabOrder = 1 + TabStop = True + object Label1: TLabel + Left = 20 + Height = 15 + Top = 25 + Width = 51 + Caption = 'Currency:' + ParentColor = False + end + object ComboBox1: TComboBox + Left = 96 + Height = 23 + Top = 21 + Width = 85 + DropDownCount = 32 + ItemHeight = 15 + OnChange = ComboBox1Change + Sorted = True + TabOrder = 0 + end + object ComboBox2: TComboBox + Left = 368 + Height = 23 + Top = 21 + Width = 85 + DropDownCount = 32 + ItemHeight = 15 + OnChange = ComboBox2Change + Sorted = True + TabOrder = 3 + end + object ConvertBtn: TBitBtn + Left = 248 + Height = 25 + Top = 20 + Width = 113 + Caption = 'Convert To' + OnClick = ConvertBtnClick + TabOrder = 2 + end + object ListBox1: TListBox + Left = 20 + Height = 188 + Top = 52 + Width = 204 + ItemHeight = 0 + TabOrder = 1 + end + object ListBox2: TListBox + Left = 248 + Height = 188 + Top = 52 + Width = 256 + ItemHeight = 0 + TabOrder = 4 + end + end + object PopupMenu1: TPopupMenu + left = 232 + top = 184 + object Copy1: TMenuItem + Caption = 'Copy' + OnClick = Copy1Click + end + object Paste1: TMenuItem + Caption = 'Paste' + OnClick = Paste1Click + end + end +end diff --git a/components/systools/examples/money_calculator/moneycal0.lrs b/components/systools/examples/money_calculator/moneycal0.lrs new file mode 100644 index 000000000..bb3efb388 --- /dev/null +++ b/components/systools/examples/money_calculator/moneycal0.lrs @@ -0,0 +1,88 @@ +{ This is an automatically generated lazarus resource file } + +LazarusResources.Add('TMoneyCalcDlg','FORMDATA',[ + 'TPF0'#13'TMoneyCalcDlg'#12'MoneyCalcDlg'#4'Left'#3#191#0#6'Height'#3#31#1#3 + +'Top'#2't'#5'Width'#3#20#2#11'BorderStyle'#7#8'bsDialog'#7'Caption'#6#16'Mon' + +'ey Calculator'#12'ClientHeight'#3#31#1#11'ClientWidth'#3#20#2#5'Color'#7#9 + +'clBtnFace'#10'Font.Color'#7#12'clWindowText'#8'OnCreate'#7#10'FormCreate'#9 + +'OnDestroy'#7#11'FormDestroy'#10'OnKeyPress'#7#12'FormKeyPress'#10'LCLVersio' + +'n'#6#7'1.9.0.0'#0#9'TGroupBox'#9'GroupBox1'#4'Left'#2#4#6'Height'#3#254#0#3 + +'Top'#2#4#5'Width'#3#209#0#7'Caption'#6#12' Calculator '#12'ClientHeight'#3 + +#234#0#11'ClientWidth'#3#205#0#8'TabOrder'#2#0#7'TabStop'#9#0#7'TBitBtn'#7'Z' + +'eroBtn'#4'Left'#2#10#6'Height'#2#28#3'Top'#3#190#0#5'Width'#2'#'#7'Caption' + +#6#1'0'#10'Font.Color'#7#6'clBlue'#7'OnClick'#7#11'NumBtnClick'#10'ParentFon' + +'t'#8#8'TabOrder'#2#1#7'TabStop'#8#0#0#7'TBitBtn'#6'DecKey'#4'Left'#2'X'#6'H' + +'eight'#2#28#3'Top'#3#190#0#5'Width'#2'#'#7'Caption'#6#1'.'#10'Font.Color'#7 + +#6'clBlue'#7'OnClick'#7#11'DecKeyClick'#10'ParentFont'#8#8'TabOrder'#2#4#7'T' + +'abStop'#8#0#0#7'TBitBtn'#8'ThreeKey'#3'Tag'#2#3#4'Left'#2'X'#6'Height'#2#28 + +#3'Top'#3#157#0#5'Width'#2'#'#7'Caption'#6#1'3'#10'Font.Color'#7#6'clBlue'#7 + +'OnClick'#7#11'NumBtnClick'#10'ParentFont'#8#8'TabOrder'#2#7#7'TabStop'#8#0#0 + +#7'TBitBtn'#6'OneKey'#3'Tag'#2#1#4'Left'#2#10#6'Height'#2#28#3'Top'#3#157#0#5 + +'Width'#2'#'#7'Caption'#6#1'1'#10'Font.Color'#7#6'clBlue'#7'OnClick'#7#11'Nu' + +'mBtnClick'#10'ParentFont'#8#8'TabOrder'#2#2#7'TabStop'#8#0#0#7'TBitBtn'#6'T' + +'woKey'#3'Tag'#2#2#4'Left'#2'1'#6'Height'#2#28#3'Top'#3#157#0#5'Width'#2'#'#7 + +'Caption'#6#1'2'#10'Font.Color'#7#6'clBlue'#7'OnClick'#7#11'NumBtnClick'#10 + +'ParentFont'#8#8'TabOrder'#2#3#7'TabStop'#8#0#0#7'TBitBtn'#6'SixKey'#3'Tag'#2 + +#6#4'Left'#2'X'#6'Height'#2#28#3'Top'#2'}'#5'Width'#2'#'#7'Caption'#6#1'6'#10 + +'Font.Color'#7#6'clBlue'#7'OnClick'#7#11'NumBtnClick'#10'ParentFont'#8#8'Tab' + +'Order'#2#10#7'TabStop'#8#0#0#7'TBitBtn'#7'FourKey'#3'Tag'#2#4#4'Left'#2#10#6 + +'Height'#2#28#3'Top'#2'}'#5'Width'#2'#'#7'Caption'#6#1'4'#10'Font.Color'#7#6 + +'clBlue'#7'OnClick'#7#11'NumBtnClick'#10'ParentFont'#8#8'TabOrder'#2#5#7'Tab' + +'Stop'#8#0#0#7'TBitBtn'#7'FiveKey'#3'Tag'#2#5#4'Left'#2'1'#6'Height'#2#28#3 + +'Top'#2'}'#5'Width'#2'#'#7'Caption'#6#1'5'#10'Font.Color'#7#6'clBlue'#7'OnCl' + +'ick'#7#11'NumBtnClick'#10'ParentFont'#8#8'TabOrder'#2#6#7'TabStop'#8#0#0#7 + +'TBitBtn'#7'NineKey'#3'Tag'#2#9#4'Left'#2'X'#6'Height'#2#28#3'Top'#2'\'#5'Wi' + +'dth'#2'#'#7'Caption'#6#1'9'#10'Font.Color'#7#6'clBlue'#7'OnClick'#7#11'NumB' + +'tnClick'#10'ParentFont'#8#8'TabOrder'#2#16#7'TabStop'#8#0#0#7'TBitBtn'#8'Se' + +'venKey'#3'Tag'#2#7#4'Left'#2#10#6'Height'#2#28#3'Top'#2'\'#5'Width'#2'#'#7 + +'Caption'#6#1'7'#10'Font.Color'#7#6'clBlue'#7'OnClick'#7#11'NumBtnClick'#10 + +'ParentFont'#8#8'TabOrder'#2#8#7'TabStop'#8#0#0#7'TBitBtn'#8'EightKey'#3'Tag' + +#2#8#4'Left'#2'1'#6'Height'#2#28#3'Top'#2'\'#5'Width'#2'#'#7'Caption'#6#1'8' + +#10'Font.Color'#7#6'clBlue'#7'OnClick'#7#11'NumBtnClick'#10'ParentFont'#8#8 + +'TabOrder'#2#9#7'TabStop'#8#0#0#7'TBitBtn'#6'AddBtn'#4'Left'#2#127#6'Height' + +#2#28#3'Top'#3#190#0#5'Width'#2'#'#7'Caption'#6#1'+'#10'Font.Color'#7#5'clRe' + +'d'#7'OnClick'#7#11'AddBtnClick'#10'ParentFont'#8#8'TabOrder'#2#12#7'TabStop' + +#8#0#0#7'TBitBtn'#6'SubBtn'#4'Left'#2#127#6'Height'#2#28#3'Top'#3#157#0#5'Wi' + +'dth'#2'#'#7'Caption'#6#1'-'#10'Font.Color'#7#5'clRed'#7'OnClick'#7#11'SubBt' + +'nClick'#10'ParentFont'#8#8'TabOrder'#2#13#7'TabStop'#8#0#0#7'TBitBtn'#6'Mul' + +'Btn'#4'Left'#2#127#6'Height'#2#28#3'Top'#2'}'#5'Width'#2'#'#7'Caption'#6#1 + +'*'#10'Font.Color'#7#5'clRed'#7'OnClick'#7#11'MulBtnClick'#10'ParentFont'#8#8 + +'TabOrder'#2#14#7'TabStop'#8#0#0#7'TBitBtn'#6'DivBtn'#4'Left'#2#127#6'Height' + +#2#28#3'Top'#2'\'#5'Width'#2'#'#7'Caption'#6#1'/'#10'Font.Color'#7#5'clRed'#7 + +'OnClick'#7#11'DivBtnClick'#10'ParentFont'#8#8'TabOrder'#2#15#7'TabStop'#8#0 + +#0#7'TBitBtn'#12'PlusMinusBtn'#4'Left'#2'1'#6'Height'#2#28#3'Top'#3#190#0#5 + +'Width'#2'#'#7'Caption'#6#3'+/-'#10'Font.Color'#7#6'clBlue'#7'OnClick'#7#17 + +'PlusMinusBtnClick'#10'ParentFont'#8#8'TabOrder'#2#11#7'TabStop'#8#0#0#7'TBi' + +'tBtn'#8'ClearBtn'#4'Left'#3#149#0#6'Height'#2#28#3'Top'#2'8'#5'Width'#2'4'#7 + +'Caption'#6#1'C'#10'Font.Color'#7#5'clRed'#7'OnClick'#7#13'ClearBtnClick'#10 + +'ParentFont'#8#8'TabOrder'#2#19#7'TabStop'#8#0#0#7'TBitBtn'#8'EqualBtn'#4'Le' + +'ft'#3#166#0#6'Height'#2'~'#3'Top'#2'\'#5'Width'#2'#'#7'Caption'#6#1'='#10'F' + +'ont.Color'#7#5'clRed'#7'OnClick'#7#13'EqualBtnClick'#10'ParentFont'#8#8'Tab' + +'Order'#2#0#7'TabStop'#8#0#0#7'TBitBtn'#13'ClearEntryBtn'#4'Left'#2'X'#6'Hei' + +'ght'#2#28#3'Top'#2'8'#5'Width'#2'8'#7'Caption'#6#2'CE'#10'Font.Color'#7#5'c' + +'lRed'#7'OnClick'#7#18'ClearEntryBtnClick'#10'ParentFont'#8#8'TabOrder'#2#18 + +#7'TabStop'#8#0#0#5'TMemo'#5'Memo1'#4'Left'#2#8#6'Height'#2#25#3'Top'#2#20#5 + +'Width'#3#193#0#9'Alignment'#7#14'taRightJustify'#9'MaxLength'#2'('#9'OnKeyD' + +'own'#7#12'Memo1KeyDown'#9'PopupMenu'#7#10'PopupMenu1'#8'ReadOnly'#9#8'TabOr' + +'der'#2#20#11'WantReturns'#8#8'WantTabs'#9#8'WordWrap'#8#0#0#7'TBitBtn'#5'BS' + ,'Btn'#4'Left'#2#10#6'Height'#2#28#3'Top'#2'8'#5'Width'#2'J'#7'Caption'#6#9'B' + +'ackspace'#10'Font.Color'#7#5'clRed'#7'OnClick'#7#10'BSBtnClick'#10'ParentFo' + +'nt'#8#8'TabOrder'#2#17#7'TabStop'#8#0#0#0#9'TGroupBox'#9'GroupBox2'#4'Left' + +#3#220#0#6'Height'#3#254#0#3'Top'#2#4#5'Width'#3'1'#1#7'Caption'#6#13' Conve' + +'rsions '#12'ClientHeight'#3#234#0#11'ClientWidth'#3'-'#1#8'TabOrder'#2#1#7 + +'TabStop'#9#0#6'TLabel'#6'Label1'#4'Left'#2#20#6'Height'#2#15#3'Top'#2#24#5 + +'Width'#2'3'#7'Caption'#6#9'Currency:'#11'ParentColor'#8#0#0#9'TComboBox'#9 + +'ComboBox1'#4'Left'#2'`'#6'Height'#2#23#3'Top'#2#24#5'Width'#2'U'#10'ItemHei' + +'ght'#2#15#8'OnChange'#7#15'ComboBox1Change'#6'Sorted'#9#8'TabOrder'#2#0#0#0 + +#9'TComboBox'#9'ComboBox2'#4'Left'#3#168#0#6'Height'#2#23#3'Top'#2'x'#5'Widt' + +'h'#2'U'#10'ItemHeight'#2#15#8'OnChange'#7#15'ComboBox2Change'#6'Sorted'#9#8 + +'TabOrder'#2#3#0#0#7'TBitBtn'#10'ConvertBtn'#4'Left'#2'0'#6'Height'#2#25#3'T' + +'op'#2'x'#5'Width'#2'q'#7'Caption'#6#10'Convert To'#7'OnClick'#7#15'ConvertB' + +'tnClick'#8'TabOrder'#2#2#0#0#8'TListBox'#8'ListBox1'#4'Left'#2#20#6'Height' + +#2'='#3'Top'#2'4'#5'Width'#3#17#1#10'ItemHeight'#2#0#8'TabOrder'#2#1#0#0#8'T' + +'ListBox'#8'ListBox2'#4'Left'#2#20#6'Height'#2'E'#3'Top'#3#152#0#5'Width'#3 + +#13#1#10'ItemHeight'#2#0#8'TabOrder'#2#4#0#0#0#10'TPopupMenu'#10'PopupMenu1' + +#4'left'#3#232#0#3'top'#3#184#0#0#9'TMenuItem'#5'Copy1'#7'Caption'#6#4'Copy' + +#7'OnClick'#7#10'Copy1Click'#0#0#9'TMenuItem'#6'Paste1'#7'Caption'#6#5'Paste' + +#7'OnClick'#7#11'Paste1Click'#0#0#0#0 +]); diff --git a/components/systools/examples/money_calculator/moneycal0.pas b/components/systools/examples/money_calculator/moneycal0.pas new file mode 100644 index 000000000..6c141f7c1 --- /dev/null +++ b/components/systools/examples/money_calculator/moneycal0.pas @@ -0,0 +1,553 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +unit moneycal0; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, + {$ENDIF} + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, Buttons, ExtCtrls, Menus, ClipBrd, + + StStrL, StDecMth, StMoney; + +const + DefaultCurrency = 'USD'; + BaseFormCaption = 'Money Calculator'; + +type + MoneyCharSet = set of Char; + MoneyOperSet = set of Char; + +type + TMoneyCalcDlg = class(TForm) + GroupBox1: TGroupBox; + ZeroBtn: TBitBtn; + DecKey: TBitBtn; + ThreeKey: TBitBtn; + OneKey: TBitBtn; + TwoKey: TBitBtn; + SixKey: TBitBtn; + FourKey: TBitBtn; + FiveKey: TBitBtn; + NineKey: TBitBtn; + SevenKey: TBitBtn; + EightKey: TBitBtn; + AddBtn: TBitBtn; + SubBtn: TBitBtn; + MulBtn: TBitBtn; + DivBtn: TBitBtn; + PlusMinusBtn: TBitBtn; + ClearBtn: TBitBtn; + EqualBtn: TBitBtn; + ClearEntryBtn: TBitBtn; + GroupBox2: TGroupBox; + Label1: TLabel; + ComboBox1: TComboBox; + ComboBox2: TComboBox; + ConvertBtn: TBitBtn; + ListBox1: TListBox; + ListBox2: TListBox; + Memo1: TMemo; + BSBtn: TBitBtn; + PopupMenu1: TPopupMenu; + Copy1: TMenuItem; + Paste1: TMenuItem; + procedure NumBtnClick(Sender: TObject); + procedure DecKeyClick(Sender: TObject); + procedure ClearBtnClick(Sender: TObject); + procedure ClearEntryBtnClick(Sender: TObject); + procedure AddBtnClick(Sender: TObject); + procedure SubBtnClick(Sender: TObject); + procedure MulBtnClick(Sender: TObject); + procedure DivBtnClick(Sender: TObject); + procedure PlusMinusBtnClick(Sender: TObject); + procedure FormKeyPress(Sender: TObject; var Key: Char); + procedure EqualBtnClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure ComboBox1Change(Sender: TObject); + procedure ConvertBtnClick(Sender: TObject); + procedure ComboBox2Change(Sender: TObject); + procedure Memo1KeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure BSBtnClick(Sender: TObject); + procedure Copy1Click(Sender: TObject); + procedure Paste1Click(Sender: TObject); + private + procedure UpdateConversionCombo; + procedure UpdateCurrencyCombo; + procedure UpdateFormCaption; + procedure ShowExchangeData(const src, trg: string); + procedure ShowCurrencyData(const Name : string); + { Private declarations } + public + MoneyChar : MoneyCharSet; + MoneyOper : MoneyOperSet; + PendOp : Char; + DFHold : Integer; + XBuffer : string[20]; + ClearOnNext, Converting : Boolean; + BaseCurrency : string; + + Currencies : TStCurrencyList; + Conversions : TStExchangeRateList; + + procedure SendKeyPress(Sender : TObject; C : Char); + procedure DoRateUpdate(Sender: TObject; NewRate: TStDecimal; + var NewDate: TDateTime); + { Public declarations } + end; + +var + MoneyCalcDlg: TMoneyCalcDlg; + +implementation + +{$R *.lfm} + +procedure TMoneyCalcDlg.UpdateFormCaption; +begin + if BaseCurrency <> '' then + Caption := BaseFormCaption + '-' + BaseCurrency + else + Caption := BaseFormCaption; +end; + +procedure TMoneyCalcDlg.FormCreate(Sender: TObject); +begin + MoneyChar := ['0'..'9', FormatSettings.DecimalSeparator, '~']; + MoneyOper := ['+', '-', '/', '*']; + DecKey.Caption := FormatSettings.DecimalSeparator; + Memo1.Lines.Text := '0'; +// Memo1.Lines[0] := '0'; + + PendOp := #0; + DFHold := 0; + XBuffer := '0'; + ClearOnNext := False; + + Currencies := TStCurrencyList.Create; + Currencies.LoadFromFile('..\..\source\run\stccy.dat'); + UpdateCurrencyCombo; + ComboBox1.Text := DefaultCurrency; + ComboBox1.ItemIndex := ComboBox1.Items.IndexOf(ComboBox1.Text); + BaseCurrency := ComboBox1.Text; + ShowCurrencyData(ComboBox1.Text); + + Conversions := TStExchangeRateList.Create; + Conversions.LoadFromFile('..\..\source\run\stccycnv.dat'); + UpdateConversionCombo; + + UpdateFormCaption; +end; + +procedure TMoneyCalcDlg.FormDestroy(Sender: TObject); +begin + Currencies.Free; + Conversions.Free; +end; + +procedure TMoneyCalcDlg.SendKeyPress(Sender : TObject; C : Char); +var + KP : Char; +begin + KP := C; + FormKeyPress(Sender,KP); +end; + +procedure TMoneyCalcDlg.NumBtnClick(Sender: TObject); +var + C : Char; +begin + C := IntToStr((Sender as TBitBtn).Tag)[1]; + SendKeyPress(Sender, C); +end; + +procedure TMoneyCalcDlg.DecKeyClick(Sender: TObject); +begin + SendKeyPress(Sender, SysUtils.DecimalSeparator); +end; + +procedure TMoneyCalcDlg.ClearBtnClick(Sender: TObject); +begin + XBuffer := '0.'; + Memo1.Lines[0] := '0.'; + PendOp := #0; + ClearOnNext := True; +end; + +procedure TMoneyCalcDlg.ClearEntryBtnClick(Sender: TObject); +begin + Memo1.Lines[0] := '0.'; + ClearOnNext := True; +end; + +procedure TMoneyCalcDlg.AddBtnClick(Sender: TObject); +begin + SendKeyPress(Sender,'+'); +end; + +procedure TMoneyCalcDlg.SubBtnClick(Sender: TObject); +begin + SendKeyPress(Sender,'-'); +end; + +procedure TMoneyCalcDlg.MulBtnClick(Sender: TObject); +begin + SendKeyPress(Sender,'*'); + +end; + +procedure TMoneyCalcDlg.DivBtnClick(Sender: TObject); +begin + SendKeyPress(Sender,'/'); +end; + +procedure TMoneyCalcDlg.PlusMinusBtnClick(Sender: TObject); +begin + SendKeyPress(Sender,'~'); +end; + +procedure TMoneyCalcDlg.FormKeyPress(Sender: TObject; var Key: Char); +var + HldOp : Char; + L : Integer; + Money1 : TStMoney; + S : string[21]; +begin + Money1 := TStMoney.Create; + + if Memo1.Lines[0] = '0' then + Memo1.Lines[0] := ''; + + try + + if Key = #13 then begin + if XBuffer = '0' then begin + XBuffer := Memo1.Lines[0]; + end + else begin + EqualBtnClick(Sender); + XBuffer := '0'; + end; + Key := #0; + ClearOnNext := True; + end; + + if Key in MoneyChar then begin + if (Length(Memo1.Lines[0]) = 0) and (Key = SysUtils.DecimalSeparator) then + Memo1.Lines[0] := '0'; + if (Key = '~') then begin + S := Memo1.Lines[0]; + + if (S[1] <> '-') then + Insert('-',S,1) + else + Delete(S,1,1); + Memo1.Lines[0] := S; + Money1.Amount.AsString := S; + Key := #0; + end else begin + if ClearOnNext then begin + Memo1.Lines[0] := ''; + ClearOnNext := False; + end; + end; + end; + + if Key in MoneyOper then begin + if not (Key in ['s', 'e', 'l']) then begin + if Memo1.Lines[0] = '' then + Memo1.Lines[0] := '0'; + if (XBuffer <> '0') then + EqualBtnClick(Sender); + XBuffer := Memo1.Lines[0]; + Money1.Amount.AsString := XBuffer; + PendOp := Key; + Key := #0; + ClearOnNext := True; + end else begin + HldOp := PendOp; + PendOp := Key; + EqualBtnClick(Sender); + PendOp := HldOp; + Key := #0; + end; + end; + + if (Key in MoneyChar) then begin + S := Memo1.Lines[0]; + L := Length(S); + if (L < Memo1.MaxLength) then begin + Memo1.Lines[0] := S + Key; + end; + + Key := #0 + end; + + Memo1.SetFocus; + Memo1.SelStart := Length(Memo1.Lines[0]); + Memo1.SelLength := 0; + + finally + Money1.Free; + end; +end; + +procedure TMoneyCalcDlg.EqualBtnClick(Sender: TObject); +var + S : AnsiString; + RV, Money : TStMoney; +begin + RV := TStMoney.Create; + Money := TStMoney.Create; + + try + if PendOp <> #0 then begin + S := Memo1.Lines[0]; + if S = '' then begin + {$IFDEF FPC} + Beep; + {$ELSE} + MessageBeep(0); + {$ENDIF} + Exit; + end; + + RV.Amount.AsString := XBuffer; + Money.Amount.AsString := S; + + case PendOp of + '+' : begin + RV.Add(Money, RV); + Memo1.Lines[0] := RV.AsString; + end; + + '-' : begin + RV.Subtract(Money, RV); + Memo1.Lines[0] := RV.AsString; + end; + + '*' : begin + RV.Multiply(StrToFloat(S), RV); + Memo1.Lines[0] := RV.AsString; + end; + + '/' : begin + if Money.IsZero then begin + Memo1.Lines[0] := 'Divide by zero error'; + PendOp := #0; + ClearOnNext := False; + end else begin + RV.Divide(StrToFloat(S), RV); + Memo1.Lines[0] := RV.AsString; + end; + end; + + end; { case } + + end; + + PendOp := #0; + ClearOnNext := True; + + Memo1.SetFocus; + Memo1.SelStart := 0; + Memo1.SelLength := 0; + finally + Money.Free; + RV.Free; + end; +end; + +procedure TMoneyCalcDlg.UpdateCurrencyCombo; +var + i : Integer; +begin + ComboBox1.Items.BeginUpdate; + ComboBox1.Items.Clear; + for i := 0 to Pred(Currencies.Count) do + ComboBox1.Items.Add(Currencies.Items[i].ISOName); + ComboBox1.Text := ''; + ComboBox1.Items.EndUpdate; +end; + +procedure TMoneyCalcDlg.UpdateConversionCombo; +var + i : Integer; +begin + ComboBox2.Items.BeginUpdate; + ComboBox2.Items.Clear; + for i := 0 to Pred(Conversions.Count) do + if Conversions.Items[i].Source = BaseCurrency then + ComboBox2.Items.Add(Conversions.Items[i].Target); + ComboBox2.Text := ''; + ComboBox2.Items.EndUpdate; + ListBox2.Clear; +end; + +procedure TMoneyCalcDlg.ShowCurrencyData(const Name : string); +var + Cur : TStCurrency; +begin + Cur := Currencies.Currencies[Name]; + ListBox1.Items.Clear; + ListBox1.Items.Add('Name: ' + Cur.Name); + ListBox1.Items.Add('ISOName: ' + Cur.ISOName); + ListBox1.Items.Add('ISOCode: ' + Cur.ISOCode); + ListBox1.Items.Add('Major: ' + Cur.UnitMajor); + ListBox1.Items.Add('Minor: ' + Cur.UnitMinor); + + if ComboBox2.Text <> '' then + ShowExchangeData(Name, ComboBox2.Text); +end; + +procedure TMoneyCalcDlg.ComboBox1Change(Sender: TObject); +begin + BaseCurrency := ComboBox1.Text; + UpdateConversionCombo; + UpdateFormCaption; + ShowCurrencyData(BaseCurrency); +end; + +procedure TMoneyCalcDlg.ConvertBtnClick(Sender: TObject); +var + CV : TStMoney; +begin + CV := TStMoney.Create; + + try + CV.ExchangeRates := Conversions; + CV.Amount.AsString := Memo1.Lines[0]; + CV.Currency := ComboBox1.Text; + + CV.Convert(ComboBox2.Text, CV); + Memo1.Lines[0] := CV.AsString; + finally + CV.Free; + end; +end; + +procedure TMoneyCalcDlg.ShowExchangeData(const src, trg : string); +var + Cur : TStCurrency; + Rate : TStExchangeRate; +begin + Cur := Currencies.Currencies[trg]; + Rate := Conversions.Rates[src, trg]; + + ListBox2.Items.Clear; + case Rate.ConversionType of + ctTriangular: begin + ListBox2.Items.Add('Name:' + #9 + Cur.Name); + ListBox2.Items.Add(src + '->' + trg + ' inter.: ' + Rate.Intermediate); + end; + + ctMultiply: begin + ListBox2.Items.Add('Name: ' + #9 + Cur.Name); + ListBox2.Items.Add(src + '->' + trg + ' multiply by: ' + Rate.Rate.AsString); + end; + + ctDivide: begin + ListBox2.Items.Add('Name: ' + #9 + Cur.Name); + ListBox2.Items.Add(src + '->' + trg + ' divide by: ' + Rate.Rate.AsString); + end; + end; + +end; + +procedure TMoneyCalcDlg.ComboBox2Change(Sender: TObject); +begin + ShowExchangeData(ComboBox1.Text, ComboBox2.Text); +end; + +procedure GetRateAndDate(var Rate, Date: string); +begin + +end; + +procedure TMoneyCalcDlg.DoRateUpdate(Sender: TObject; + NewRate : TStDecimal; var NewDate : TDateTime); +var + ARate, ADate : string; +begin + GetRateAndDate(ARate, ADate); + NewRate.AsString := ARate; + NewDate := StrToDateTime(ADate); +end; + + + +procedure TMoneyCalcDlg.Memo1KeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if Key = VK_DOWN then + Key := 0; +end; + +procedure TMoneyCalcDlg.BSBtnClick(Sender: TObject); +begin + Memo1.Lines[0] := Copy(Memo1.Lines[0], 1, Length(Memo1.Lines[0]) - 1); + if Length(Memo1.Lines[0]) = 0 then + ClearBtnClick(ClearBtn); +end; + +procedure TMoneyCalcDlg.Copy1Click(Sender: TObject); +begin + Memo1.SelectAll; + Memo1.CopyToClipboard; + Memo1.SelStart := 0; +end; + +procedure TMoneyCalcDlg.Paste1Click(Sender: TObject); +var + S : string; + IsNeg : Boolean; +begin + IsNeg := False; + S := Clipboard.AsText; + if (S[1] = '-') then begin + IsNeg := True; + S := Copy(S, 2, Length(S) - 1); + end; + + if IsStrNumericL(S, '0123456789' + SysUtils.DecimalSeparator) then begin + if IsNeg then S := '-' + S; + Memo1.Lines[0] := S; + end; +end; + +end. + diff --git a/components/systools/examples/money_calculator/moneycalc.lpi b/components/systools/examples/money_calculator/moneycalc.lpi new file mode 100644 index 000000000..3205b405a --- /dev/null +++ b/components/systools/examples/money_calculator/moneycalc.lpi @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <General> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="moneycalc"/> + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + <Icon Value="0"/> + </General> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="laz_systools"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="2"> + <Unit0> + <Filename Value="moneycalc.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="MonyCalc"/> + </Unit0> + <Unit1> + <Filename Value="moneycal0.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="MoneyCalcDlg"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="moneycalc"/> + </Target> + <SearchPaths> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/systools/examples/money_calculator/moneycalc.lpr b/components/systools/examples/money_calculator/moneycalc.lpr new file mode 100644 index 000000000..4d010b135 --- /dev/null +++ b/components/systools/examples/money_calculator/moneycalc.lpr @@ -0,0 +1,38 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +program MoneyCalc; + +uses + Forms, Interfaces, + moneycal0 in 'moneycal0.pas' {MoneyCalcDlg}; + +{$R *.RES} + +begin + Application.Initialize; + Application.CreateForm(TMoneyCalcDlg, MoneyCalcDlg); + Application.Run; +end. diff --git a/components/systools/laz_systools.lpk b/components/systools/laz_systools.lpk new file mode 100644 index 000000000..0513f5cbe --- /dev/null +++ b/components/systools/laz_systools.lpk @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <Package Version="4"> + <PathDelim Value="\"/> + <Name Value="laz_systools"/> + <Author Value="Original author: TurboPower Software"/> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="source\include;source\run"/> + <OtherUnitFiles Value="source\run"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)\run"/> + </SearchPaths> + </CompilerOptions> + <Description Value="Lazarus port of TurboPower SysTools (Delphi version at https://sourceforge.net/projects/tpsystools/) - runtime package"/> + <License Value="MPL 1.1"/> + <Version Major="4" Release="4"/> + <Files Count="21"> + <Item1> + <Filename Value="source\run\stbarc.pas"/> + <UnitName Value="StBarC"/> + </Item1> + <Item2> + <Filename Value="source\run\stbase.pas"/> + <UnitName Value="StBase"/> + </Item2> + <Item3> + <Filename Value="source\run\stconst.pas"/> + <UnitName Value="StConst"/> + </Item3> + <Item4> + <Filename Value="source\run\stbarpn.pas"/> + <UnitName Value="StBarPN"/> + </Item4> + <Item5> + <Filename Value="source\run\ststrl.pas"/> + <UnitName Value="StStrL"/> + </Item5> + <Item6> + <Filename Value="source\include\stdefine.inc"/> + <Type Value="Include"/> + </Item6> + <Item7> + <Filename Value="source\run\st2dbarc.pas"/> + <UnitName Value="St2DBarC"/> + </Item7> + <Item8> + <Filename Value="source\run\stdate.pas"/> + <UnitName Value="StDate"/> + </Item8> + <Item9> + <Filename Value="source\run\stutils.pas"/> + <UnitName Value="StUtils"/> + </Item9> + <Item10> + <Filename Value="source\run\stcrc.pas"/> + <UnitName Value="StCRC"/> + </Item10> + <Item11> + <Filename Value="source\run\sthash.pas"/> + <UnitName Value="StHASH"/> + </Item11> + <Item12> + <Filename Value="source\run\sttohtml.pas"/> + <UnitName Value="StToHTML"/> + </Item12> + <Item13> + <Filename Value="source\run\ststrms.pas"/> + <UnitName Value="StStrms"/> + </Item13> + <Item14> + <Filename Value="source\run\stdict.pas"/> + <UnitName Value="StDict"/> + </Item14> + <Item15> + <Filename Value="source\run\stinistm.pas"/> + <UnitName Value="StIniStm"/> + </Item15> + <Item16> + <Filename Value="source\run\stdecmth.pas"/> + <UnitName Value="StDecMth"/> + </Item16> + <Item17> + <Filename Value="source\run\stexpr.pas"/> + <UnitName Value="StExpr"/> + </Item17> + <Item18> + <Filename Value="source\run\stmath.pas"/> + <UnitName Value="StMath"/> + </Item18> + <Item19> + <Filename Value="source\run\stfin.pas"/> + <UnitName Value="StFIN"/> + </Item19> + <Item20> + <Filename Value="source\run\stdatest.pas"/> + <UnitName Value="StDateSt"/> + </Item20> + <Item21> + <Filename Value="source\run\stmoney.pas"/> + <UnitName Value="StMoney"/> + </Item21> + </Files> + <RequiredPkgs Count="2"> + <Item1> + <PackageName Value="LCL"/> + </Item1> + <Item2> + <PackageName Value="FCL"/> + </Item2> + </RequiredPkgs> + <UsageOptions> + <UnitPath Value="$(PkgOutDir)"/> + </UsageOptions> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <CustomOptions Items="ExternHelp" Version="2"> + <_ExternHelp Items="Count"/> + </CustomOptions> + </Package> +</CONFIG> diff --git a/components/systools/laz_systools.pas b/components/systools/laz_systools.pas new file mode 100644 index 000000000..0050e464b --- /dev/null +++ b/components/systools/laz_systools.pas @@ -0,0 +1,17 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit laz_systools; + +{$warn 5023 off : no warning about unused units} +interface + +uses + StBarC, StBase, StConst, StBarPN, StStrL, St2DBarC, StDate, StUtils, StCRC, + StHASH, StToHTML, StStrms, StDict, StIniStm, StDecMth, StExpr, StMath, + StFIN, StDateSt, StMoney; + +implementation + +end. diff --git a/components/systools/laz_systools_design.lpk b/components/systools/laz_systools_design.lpk new file mode 100644 index 000000000..4f44f5c49 --- /dev/null +++ b/components/systools/laz_systools_design.lpk @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <Package Version="4"> + <PathDelim Value="\"/> + <Name Value="laz_systools_design"/> + <Type Value="RunAndDesignTime"/> + <Author Value="Original author: TurboPower Software"/> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="source\include"/> + <OtherUnitFiles Value="source\design"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)\design"/> + </SearchPaths> + </CompilerOptions> + <Description Value="Lazarus port of TurboPower SysTools (Delphi version at https://sourceforge.net/projects/tpsystools/) - designtime package."/> + <License Value="MPL-1.1"/> + <Version Major="4" Release="4"/> + <Files Count="1"> + <Item1> + <Filename Value="source\design\StReg.pas"/> + <HasRegisterProc Value="True"/> + <UnitName Value="StReg"/> + </Item1> + </Files> + <RequiredPkgs Count="2"> + <Item1> + <PackageName Value="laz_systools"/> + </Item1> + <Item2> + <PackageName Value="FCL"/> + </Item2> + </RequiredPkgs> + <UsageOptions> + <UnitPath Value="$(PkgOutDir)"/> + </UsageOptions> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + </Package> +</CONFIG> diff --git a/components/systools/laz_systools_design.pas b/components/systools/laz_systools_design.pas new file mode 100644 index 000000000..e3fafd059 --- /dev/null +++ b/components/systools/laz_systools_design.pas @@ -0,0 +1,22 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit laz_systools_design; + +{$warn 5023 off : no warning about unused units} +interface + +uses + StReg, LazarusPackageIntf; + +implementation + +procedure Register; +begin + RegisterUnit('StReg', @StReg.Register); +end; + +initialization + RegisterPackage('laz_systools_design', @Register); +end. diff --git a/components/systools/laz_systoolsdb.lpk b/components/systools/laz_systoolsdb.lpk new file mode 100644 index 000000000..861a15faf --- /dev/null +++ b/components/systools/laz_systoolsdb.lpk @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <Package Version="4"> + <PathDelim Value="\"/> + <Name Value="laz_systoolsdb"/> + <Author Value="Turbo Power Software"/> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="source\include;source\db"/> + <OtherUnitFiles Value="source\db"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)\run-db"/> + </SearchPaths> + </CompilerOptions> + <Description Value="Lazarus port of Turbo Power SysTools database components - runtime package"/> + <License Value="MPL 1.1"/> + <Version Major="4" Release="4"/> + <Files Count="3"> + <Item1> + <Filename Value="source\db\stdb2dbc.pas"/> + <UnitName Value="StDb2DBC"/> + </Item1> + <Item2> + <Filename Value="source\db\stdbbarc.pas"/> + <UnitName Value="StDbBarC"/> + </Item2> + <Item3> + <Filename Value="source\db\stdbpnbc.pas"/> + <UnitName Value="StDbPNBC"/> + </Item3> + </Files> + <RequiredPkgs Count="3"> + <Item1> + <PackageName Value="laz_systools"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + <Item3> + <PackageName Value="FCL"/> + </Item3> + </RequiredPkgs> + <UsageOptions> + <UnitPath Value="$(PkgOutDir)"/> + </UsageOptions> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + </Package> +</CONFIG> diff --git a/components/systools/laz_systoolsdb.pas b/components/systools/laz_systoolsdb.pas new file mode 100644 index 000000000..588cfedd6 --- /dev/null +++ b/components/systools/laz_systoolsdb.pas @@ -0,0 +1,15 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit laz_systoolsdb; + +{$warn 5023 off : no warning about unused units} +interface + +uses + StDb2DBC, StDbBarC, StDbPNBC; + +implementation + +end. diff --git a/components/systools/laz_systoolsdb_design.lpk b/components/systools/laz_systoolsdb_design.lpk new file mode 100644 index 000000000..1fea18023 --- /dev/null +++ b/components/systools/laz_systoolsdb_design.lpk @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <Package Version="4"> + <PathDelim Value="\"/> + <Name Value="laz_systoolsdb_design"/> + <Type Value="DesignTime"/> + <Author Value="TurboPower Software"/> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="source\design"/> + <OtherUnitFiles Value="source\design"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)\"/> + </SearchPaths> + </CompilerOptions> + <Description Value="Lazarus port of TurboPower SysTools database components - designtime package"/> + <License Value="MPL 1.1"/> + <Version Major="4" Release="4"/> + <Files Count="1"> + <Item1> + <Filename Value="source\design\StRegDb.pas"/> + <HasRegisterProc Value="True"/> + <AddToUsesPkgSection Value="False"/> + </Item1> + </Files> + <RequiredPkgs Count="3"> + <Item1> + <PackageName Value="IDEIntf"/> + </Item1> + <Item2> + <PackageName Value="laz_systoolsdb"/> + </Item2> + <Item3> + <PackageName Value="FCL"/> + </Item3> + </RequiredPkgs> + <UsageOptions> + <UnitPath Value="$(PkgOutDir)"/> + </UsageOptions> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + </Package> +</CONFIG> diff --git a/components/systools/laz_systoolsdb_design.pas b/components/systools/laz_systoolsdb_design.pas new file mode 100644 index 000000000..b56594cad --- /dev/null +++ b/components/systools/laz_systoolsdb_design.pas @@ -0,0 +1,22 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit laz_systoolsdb_design; + +{$warn 5023 off : no warning about unused units} +interface + +uses + StRegDb, LazarusPackageIntf; + +implementation + +procedure Register; +begin + RegisterUnit('StRegDb', @StRegDb.Register); +end; + +initialization + RegisterPackage('laz_systoolsdb_design', @Register); +end. diff --git a/components/systools/readme.txt b/components/systools/readme.txt new file mode 100644 index 000000000..6ec660716 --- /dev/null +++ b/components/systools/readme.txt @@ -0,0 +1,78 @@ +TurboPower SysTools + + +Table of contents + +1. Introduction +2. Package names +3. Installation +4. Version history +4.1 Release 4.03 + +============================================== + + +1. Introduction + + +SysTools is a library of utility routines & classes for Borland +Delphi, C++Builder, & environments that support COM. It includes 1-D & +2-D bar codes, sorting, money routines, logging, high-precision math, +a run-time math expression analyzer, & much more. + +This is a source-only release of TurboPower SysTools. It includes +designtime and runtime packages for Delphi 3 through 7 and C++Builder +3 through 6. + +============================================== + +2. Package names + + +TurboPower SysTools package names have the following form: + + SNNN_KVV.* + | || + | |+------ VV VCL version (30=Delphi 3, 40=Delphi 4, 70=Delphi 7) + | +------- K Kind of package (R=runtime, D=designtime) + | + +----------- NNN Product version number (e.g., 403=version 4.03) + + +For example, the SysTools designtime package files for Delphi 7 have +the filename S403_D70.*. + +============================================== + +3. Installation + + +To install TurboPower SysTools into your IDE, take the following +steps: + + 1. Unzip the release files into a directory (e.g., d:\systools). + + 2. Start Delphi or C++Builder. + + 3. Add the source subdirectory (e.g., d:\systools\source) to the + IDE's library path. + + 4. Open & install the designtime package specific to the IDE being + used. The IDE should notify you the components have been + installed. + + 5. Make sure the PATH environmental variable contains the directory + in which the compiled packages (i.e., BPL or DPL files) were + placed. + +============================================== + +4. Version history + + +4.1 Release 4.03 + + Bug fixes + ------------------------------------------------------------- + - Range error in TimeToTimeStringPrim Routine + - Added empty string case handling to TrimLeadS diff --git a/components/systools/readme404pre.txt b/components/systools/readme404pre.txt new file mode 100644 index 000000000..ae85e5441 --- /dev/null +++ b/components/systools/readme404pre.txt @@ -0,0 +1,64 @@ +TurboPower SysTools -- Version 4.04 Pre-Release + + +Table of contents + +1. Introduction +2. Package names +3. Installation + + +============================================== + + +1. Introduction + +This is a "pre-release" of SysTools version 4.04. It contains only the +Delphi packages for Delphi 2005 and Delphi 2006. It does not contain any +other enhancements or bug fixes that may have been made since the release of +version 4.03. To compile the Delphi 2005 and Delphi 2006 packages, you will +still need all of the source files from version 4.03. + +============================================== + +2. Package names + + +The Delphi 2005 runtime packages are S404_R90.dpk and S404BR90.dpk. The +designtime packages are S404_D90.dpk and S404BD90.dpk. + +The Delphi 2006 runtime packages are S404_R100.dpk and S404BR100.dpk. The +designtime packages are S404_D100.dpk and S404BD100.dpk. + +============================================== + + +3. Installation + + +To install TurboPower SysTools into your Delphi 2005 or 2006 IDE, take the following steps: + + 1. Unzip the release files into the packages directory of your SysTools 4.03 installation + (e.g., c:\turbopower\systools\packages). + + 2. Start Delphi 2005 or 2006. + + 3. Add the source subdirectory (e.g., c:\turbopower\systools\source) to the IDE's + library path. + + 4. Open & compile the runtime packages specific to the IDE being used. + (S404_R90.bdsproj and S404BR90.bdsproj for Delphi 2005, and S404_R100.bdsproj + and S404BR100.bdsproj for Delphi 2006.) + + 5. Open & compile the designtime packages specific to the IDE being used. + (S404_D90.bdsproj and S404BD90.bdsproj for Delphi 2005, and S404_D100.bdsproj + and S404BD100.bdsproj for Delphi 2006.) + + 6. Install the designtime packages into the IDE by using the Component/Install + Packages menu option. From there, click the "Add" button and then navigate + to the location of your newly-compiled designtime packages. (S404_D90.bpl and + S404BD90.bpl for Delphi 2005, and S404_D100.bpl and S404BD100.bpl for Delphi + 2006.) By default, the Delphi compiler places the compiled packages in the + C:\Documents and Settings\<Your User Name>\My Documents\Borland Studio Projects\Bpl + directory. + diff --git a/components/systools/source/db/stdb2dbc.pas b/components/systools/source/db/stdb2dbc.pas new file mode 100644 index 000000000..7fbd25688 --- /dev/null +++ b/components/systools/source/db/stdb2dbc.pas @@ -0,0 +1,358 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDb2DBC.pas 4.04 *} +{*********************************************************} +{* SysTools: Data-aware Two-Dimensional Barcodes *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit StDb2DBC; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, + {$ENDIF} + SysUtils, + Classes, + St2DBarC, + Db, + DbCtrls; + +type + + TStDbPDF417Barcode = class(TStPDF417Barcode) + protected {private} + {.Z+} + FCaptionDataLink : TFieldDataLink; + FCodeDataLink : TFieldDataLink; + + procedure CaptionDataChange(Sender : TObject); + procedure CodeDataChange(Sender : TObject); + function GetCaptionDataField : string; + function GetCodeDataField : string; + function GetDataSource : TDataSource; + procedure SetCaptionDataField(const Value : string); + procedure SetCodeDataField(const Value : string); + procedure SetDataSource(Value : TDataSource); + + public + constructor Create(AOwner : TComponent); override; + destructor Destroy; + override; + {.Z+} + published + property Code stored False; + property Caption stored False; + + property CaptionDataField : string + read GetCaptionDataField write SetCaptionDataField; + property CodeDataField : string + read GetCodeDataField write SetCodeDataField; + + property DataSource : TDataSource read GetDataSource write SetDataSource; + end; + + TStDbMaxiCodeBarcode = class(TStMaxiCodeBarcode) + protected {private} + {.Z+} + FCaptionDataLink : TFieldDataLink; + FCodeDataLink : TFieldDataLink; + FCountryCodeDataLink : TFieldDataLink; + FPostalCodeDataLink : TFieldDataLink; + FServiceClassDataLink : TFieldDataLink; + + procedure CaptionDataChange (Sender : TObject); + procedure CodeDataChange (Sender : TObject); + procedure CountryCodeChange (Sender : TObject); + + function GetCaptionDataField : string; + function GetCodeDataField : string; + function GetCountryCodeDataField : string; + function GetDataSource : TDataSource; + function GetPostalCodeDataField : string; + function GetServiceClassDataField : string; + + procedure PostalCodeChange (Sender : TObject); + procedure ServiceClassChange (Sender : TObject); + + procedure SetCaptionDataField (const Value : string); + procedure SetCodeDataField (const Value : string); + procedure SetCountryCodeDataField (const Value : string); + procedure SetDataSource (Value : TDataSource); + procedure SetPostalCodeDataField (const Value : string); + procedure SetServiceClassDataField (const Value : string); + + public + constructor Create(AOwner : TComponent); override; + destructor Destroy; + override; + {.Z+} + published + property Code stored False; + property Caption stored False; + + property CaptionDataField : string + read GetCaptionDataField write SetCaptionDataField; + property CarrierCountryCodeDataField : string + read GetCountryCodeDataField write SetCountryCodeDataField; + property CarrierPostalCodeDataField : string + read GetPostalCodeDataField write SetPostalCodeDataField; + property CarrierServiceClassDataField : string + read GetServiceClassDataField write SetServiceClassDataField; + property CodeDataField : string + read GetCodeDataField write SetCodeDataField; + + property DataSource : TDataSource read GetDataSource write SetDataSource; + end; + +implementation + +{ TStDbPDF417Barcode } + +constructor TStDbPDF417Barcode.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + FCaptionDataLink := TFieldDataLink.Create; + FCaptionDataLink.OnDataChange := CaptionDataChange; + FCodeDataLink := TFieldDataLink.Create; + FCodeDataLink.OnDataChange := CodeDataChange; +end; + +destructor TStDbPDF417Barcode.Destroy; +begin + FCaptionDataLink.OnDataChange := nil; + FCaptionDataLink.Free; + FCaptionDataLink := nil; + FCodeDataLink.OnDataChange := nil; + FCodeDataLink.Free; + FCodeDataLink := nil; + + inherited Destroy; +end; + +procedure TStDbPDF417Barcode.CaptionDataChange(Sender : TObject); +begin + if FCaptionDataLink.Field = nil then + Caption := '12345678922' + else + Caption := FCaptionDataLink.Field.DisplayText; +end; + +procedure TStDbPDF417Barcode.CodeDataChange(Sender : TObject); +begin + if FCodeDataLink.Field = nil then + Code := '12345678922' + else + Code := FCodeDataLink.Field.DisplayText; +end; + + +function TStDbPDF417Barcode.GetCaptionDataField : string; +begin + Result := FCaptionDataLink.FieldName; +end; + +function TStDbPDF417Barcode.GetCodeDataField : string; +begin + Result := FCodeDataLink.FieldName; +end; + +function TStDbPDF417Barcode.GetDataSource : TDataSource; +begin + Result := FCaptionDataLink.DataSource +end; + +procedure TStDbPDF417Barcode.SetCaptionDataField(const Value : string); +begin + FCaptionDataLink.FieldName := Value; +end; + +procedure TStDbPDF417Barcode.SetCodeDataField(const Value : string); +begin + FCodeDataLink.FieldName := Value; +end; + +procedure TStDbPDF417Barcode.SetDataSource(Value : TDataSource); +begin + FCaptionDataLink.DataSource := Value; + FCodeDataLink.DataSource := Value; +end; + +{ TStDbMaxiCodeBarcode } + +constructor TStDbMaxiCodeBarcode.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + FCaptionDataLink := TFieldDataLink.Create; + FCaptionDataLink.OnDataChange := CaptionDataChange; + FCodeDataLink := TFieldDataLink.Create; + FCodeDataLink.OnDataChange := CodeDataChange; + FCountryCodeDataLink := TFieldDataLink.Create; + FCountryCodeDataLink.OnDataChange := CountryCodeChange; + FPostalCodeDataLink := TFieldDataLink.Create; + FPostalCodeDataLink.OnDataChange := PostalCodeChange; + FServiceClassDataLink := TFieldDataLink.Create; + FServiceClassDataLink.OnDataChange := ServiceClassChange; +end; + +destructor TStDbMaxiCodeBarcode.Destroy; +begin + FCaptionDataLink.OnDataChange := nil; + FCaptionDataLink.Free; + FCaptionDataLink := nil; + FCodeDataLink.OnDataChange := nil; + FCodeDataLink.Free; + FCodeDataLink := nil; + FCountryCodeDataLink.OnDataChange := nil; + FCountryCodeDataLink.Free; + FCountryCodeDataLink := nil; + FPostalCodeDataLink.OnDataChange := nil; + FPostalCodeDataLink.Free; + FPostalCodeDataLink := nil; + FServiceClassDataLink.OnDataChange := nil; + FServiceClassDataLink.Free; + FServiceClassDataLink := nil; + + inherited Destroy; +end; + +procedure TStDbMaxiCodeBarcode.CaptionDataChange(Sender : TObject); +begin + if FCaptionDataLink.Field = nil then + Caption := '12345678922' + else + Caption := FCaptionDataLink.Field.DisplayText; +end; + +procedure TStDbMaxiCodeBarcode.CodeDataChange(Sender : TObject); +begin + if FCodeDataLink.Field = nil then + Code := '12345678922' + else + Code := FCodeDataLink.Field.DisplayText; +end; + +procedure TStDbMaxiCodeBarcode.CountryCodeChange (Sender : TObject); +begin + if FCountryCodeDataLink.Field = nil then + CarrierCountryCode := 0 + else + CarrierCountryCode := FCountryCodeDataLink.Field.AsInteger; +end; + +function TStDbMaxiCodeBarcode.GetCaptionDataField : string; +begin + Result := FCaptionDataLink.FieldName; +end; + +function TStDbMaxiCodeBarcode.GetCodeDataField : string; +begin + Result := FCodeDataLink.FieldName; +end; + +function TStDbMaxiCodeBarcode.GetCountryCodeDataField : string; +begin + Result := FCountryCodeDataLink.FieldName; +end; + +function TStDbMaxiCodeBarcode.GetDataSource : TDataSource; +begin + Result := FCaptionDataLink.DataSource +end; + +function TStDbMaxiCodeBarcode.GetPostalCodeDataField : string; +begin + Result := FPostalCodeDataLink.FieldName; +end; + +function TStDbMaxiCodeBarcode.GetServiceClassDataField : string; +begin + Result := FServiceClassDataLink.FieldName; +end; + +procedure TStDbMaxiCodeBarcode.PostalCodeChange (Sender : TObject); +begin + if FPostalCodeDataLink.Field = nil then + CarrierPostalCode := '000' + else + CarrierPostalCode := FPostalCodeDataLink.Field.DisplayText; +end; + +procedure TStDbMaxiCodeBarcode.ServiceClassChange (Sender : TObject); +begin + if FServiceClassDataLink.Field = nil then + CarrierServiceClass := 0 + else + CarrierServiceClass := FServiceClassDataLink.Field.AsInteger; +end; + +procedure TStDbMaxiCodeBarcode.SetCaptionDataField(const Value : string); +begin + FCaptionDataLink.FieldName := Value; +end; + +procedure TStDbMaxiCodeBarcode.SetCodeDataField(const Value : string); +begin + FCodeDataLink.FieldName := Value; +end; + +procedure TStDbMaxiCodeBarcode.SetCountryCodeDataField (const Value : string); +begin + FCountryCodeDataLink.FieldName := Value; +end; + +procedure TStDbMaxiCodeBarcode.SetDataSource(Value : TDataSource); +begin + FCaptionDataLink.DataSource := Value; + FCodeDataLink.DataSource := Value; + FCountryCodeDataLink.DataSource := Value; + FPostalCodeDataLink.DataSource := Value; + FServiceClassDataLink.DataSource := Value; +end; + +procedure TStDbMaxiCodeBarcode.SetPostalCodeDataField (const Value : string); +begin + FPostalCodeDataLink.FieldName := Value; +end; + +procedure TStDbMaxiCodeBarcode.SetServiceClassDataField (const Value : string); +begin + FServiceClassDataLink.FieldName := Value; +end; + +end. diff --git a/components/systools/source/db/stdbbarc.pas b/components/systools/source/db/stdbbarc.pas new file mode 100644 index 000000000..186b9aa30 --- /dev/null +++ b/components/systools/source/db/stdbbarc.pas @@ -0,0 +1,136 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDbBarC.pas 4.04 *} +{*********************************************************} +{* SysTools: data aware bar code components *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit StDbBarC; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, DbTables, + {$ENDIF} + Classes, //ClipBrd, + Controls, Graphics, SysUtils, + Db, DbCtrls, + StConst, StBarC; + +type + TStDbBarCode = class(TStBarCode) + protected {private} + {.Z+} + FDataLink : TFieldDataLink; + + procedure DataChange(Sender : TObject); + function GetDataField : string; + function GetDataSource : TDataSource; + procedure SetDataField(const Value : string); + procedure SetDataSource(Value : TDataSource); + + public + constructor Create(AOwner : TComponent); + override; + destructor Destroy; + override; + {.Z+} + published + property Code + stored False; + + property DataField : string + read GetDataField + write SetDataField; + + property DataSource : TDataSource + read GetDataSource + write SetDataSource; + end; + + +implementation + + +{*** TStDbBarCode ***} + +constructor TStDbBarCode.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + FDataLink := TFieldDataLink.Create; + FDataLink.OnDataChange := DataChange; +end; + +procedure TStDbBarCode.DataChange(Sender : TObject); +begin + if FDataLink.Field = nil then + Code := '12345678922' + else + Code := FDataLink.Field.DisplayText; +end; + +destructor TStDbBarCode.Destroy; +begin + FDataLink.OnDataChange := nil; + FDataLink.Free; + FDataLink := nil; + + inherited Destroy; +end; + +function TStDbBarCode.GetDataField : string; +begin + Result := FDataLink.FieldName; +end; + +function TStDbBarCode.GetDataSource : TDataSource; +begin + Result := FDataLink.DataSource +end; + +procedure TStDbBarCode.SetDataField(const Value : string); +begin + FDataLink.FieldName := Value; +end; + +procedure TStDbBarCode.SetDataSource(Value : TDataSource); +begin + FDataLink.DataSource := Value; +end; + + +end. diff --git a/components/systools/source/db/stdbpnbc.pas b/components/systools/source/db/stdbpnbc.pas new file mode 100644 index 000000000..b2de9ea2c --- /dev/null +++ b/components/systools/source/db/stdbpnbc.pas @@ -0,0 +1,133 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDbPNBC.pas 4.04 *} +{*********************************************************} +{* SysTools: data aware PostNet Bar Code component *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} +//{$I STDEFINE.INC} + +unit StDbPNBC; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, DBTables, + {$ENDIF} + Classes, ClipBrd, Controls, Graphics, SysUtils, + Db, DbCtrls, + StConst, StBarPN; + +type + TStDbPNBarCode = class(TStPNBarCode) + protected {private} + {.Z+} + FDataLink : TFieldDataLink; + + procedure DataChange(Sender : TObject); + function GetDataField : string; + function GetDataSource : TDataSource; + procedure SetDataField(const Value : string); + procedure SetDataSource(Value : TDataSource); + + public + constructor Create(AOwner : TComponent); + override; + destructor Destroy; + override; + {.Z+} + published + property PostalCode + stored False; + + property DataField : string + read GetDataField + write SetDataField; + + property DataSource : TDataSource + read GetDataSource + write SetDataSource; + end; + + +implementation + +{*** TStDbPNBarCode ***} + +constructor TStDbPNBarCode.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + FDataLink := TFieldDataLink.Create; + FDataLink.OnDataChange := DataChange; +end; + +procedure TStDbPNBarCode.DataChange(Sender : TObject); +begin + if FDataLink.Field = nil then + PostalCode := '12345' + else + PostalCode := FDataLink.Field.DisplayText; +end; + +destructor TStDbPNBarCode.Destroy; +begin + FDataLink.OnDataChange := nil; + FDataLink.Free; + FDataLink := nil; + + inherited Destroy; +end; + +function TStDbPNBarCode.GetDataField : string; +begin + Result := FDataLink.FieldName; +end; + +function TStDbPNBarCode.GetDataSource : TDataSource; +begin + Result := FDataLink.DataSource +end; + +procedure TStDbPNBarCode.SetDataField(const Value : string); +begin + FDataLink.FieldName := Value; +end; + +procedure TStDbPNBarCode.SetDataSource(Value : TDataSource); +begin + FDataLink.DataSource := Value; +end; + + +end. diff --git a/components/systools/source/design/StReg.pas b/components/systools/source/design/StReg.pas new file mode 100644 index 000000000..68e1b5534 --- /dev/null +++ b/components/systools/source/design/StReg.pas @@ -0,0 +1,239 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StReg.pas 4.04 *} +{*********************************************************} +{* SysTools: Component Registration Unit *} +{*********************************************************} + +//{$I StDefine.inc} + +{$R StReg.r32} + +unit StReg; + +interface + +uses + Classes +{$IFDEF FPC} + ;//PropEdits //, LazarusPackageIntf //, FieldsEditor, ComponentEditors +{$ELSE} + {$IFDEF VERSION6} + DesignIntf, + DesignEditorsM + {$ELSE} + DsgnIntfM + {$ENDIF} +{$ENDIF} + +procedure Register; + +implementation + +uses + StBase, + +// StAbout0, + + { components } + St2DBarC, + StBarC, + StBarPN, + (*, + StNetCon, + StNetMsg, + StNetPfm, + StNVBits, + StNVColl, + StNVDict, + StNVDQ, + StNVLAry, + StNVList, + StNVLMat, + StNVSCol, + StNVTree, + StRegEx, + StSpawn, + *) + StToHTML, + (* + StVInfo, + StWMDCpy, + + {forces these units to be compiled when components are installed} + {vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv} + StAstro, + StAstroP, + StBCD, + StBits, + StColl, + *) + StConst, + StCrc, + StDate, + (* + StDateSt, + StDict, + StDQue, + StEclpse, + *) + StExpr, + StFIN, + (* + StFirst, + StHASH, + StJup, + StJupsat, + StLArr, + StList, + StMars, + *) + StMath, + (* + StMerc, + StMime, + StNeptun, + StNet, + StNetApi, + StNVCont, + StOStr, + StPluto, + StPQueue, + StRegIni, + StSaturn, + StSort, + StStat, + StStrL, + StStrms, + StStrS, + StStrW, + StStrZ, + StText, + StTree, + StUranus, + *) + StUtils, + (* + StVArr, + StVenus, + { new units in ver 4: } + StIniStm, + StMerge, + StSystem, + StTxtDat, + StDecMth, + *) + StMoney + (* + StRandom, + StNTLog, + { !!! StExpEng unit designed to handle problem with initialization } + { section in C++Builder; should NOT be included in Registration unit } + { nor in Run-time package !!! } + {StExpEng,} + StExpLog, + StGenLog, + StPtrns, + + + {^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^} + StPropEd + *); + +procedure Register; +begin + (* + RegisterPropertyEditor(TypeInfo(string), TStComponent, 'Version', + TStVersionProperty); + RegisterPropertyEditor(TypeInfo(string), TStBaseEdit, 'Version', + TStVersionProperty); + RegisterPropertyEditor(TypeInfo(string), TStBarCode, 'Version', + TStVersionProperty); + RegisterPropertyEditor(TypeInfo(string), TStPNBarCode, 'Version', + TStVersionProperty); + RegisterPropertyEditor(TypeInfo(string), TStRegEx, 'InputFile', + TStGenericFileNameProperty); + RegisterPropertyEditor(TypeInfo(string), TStRegEx, 'OutputFile', + TStGenericFileNameProperty); + RegisterPropertyEditor(TypeInfo(string), TStFileToHTML, 'InFileName', + TStGenericFileNameProperty); + RegisterPropertyEditor(TypeInfo(string), TStFileToHTML, 'OutFileName', + TStGenericFileNameProperty); + RegisterPropertyEditor(TypeInfo(string), TStVersionInfo, 'FileName', + TStFileNameProperty); + RegisterPropertyEditor(TypeInfo(string), TStSpawnApplication, 'FileName', + TStGenericFileNameProperty); + *) + + RegisterComponents('SysTools', + [ + { + TStNetConnection, + TStNetPerformance, + TStNetMessage, + TStVersionInfo, + } + TStExpression, + TStExpressionEdit, + TStBarCode, + TStPNBarCode, + { + TStRegEx, + TStWMDataCopy, + } + TStFileToHTML, + { + TStSpawnApplication, + } +// new in SysTools 4 + TStPDF417Barcode, + TStMaxiCodeBarcode + { + TStGeneralLog, +{.$IFNDEF BCB} {!!! problem with initialization section in BCB } + TStExceptionLog, +{.$ENDIF} + TStNTEventLog + } + ]); + + (* + {non-visual container class components} + RegisterComponents('SysTools (CC)', + [TStNVBits, + TStNVCollection, + TStNVDictionary, + TStNVDQue, + TStNVLArray, + TStNVList, + TStNVLMatrix, + TStNVSortedCollection, + TStNVTree]); + *) +end; + +end. diff --git a/components/systools/source/design/StReg.rc b/components/systools/source/design/StReg.rc new file mode 100644 index 000000000..aa1a59a47 --- /dev/null +++ b/components/systools/source/design/StReg.rc @@ -0,0 +1,945 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ +/**************************************************************************** + + +streg.rc + +produced by Borland Resource Workshop + + +*****************************************************************************/ + + +STTEMPLATE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTBARCODE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 03 33 33 33 33 33 33 33 33' + '30 33 33 03 33 33 33 33 33 33 33 33 30 33 33 03' + '03 00 30 30 33 00 30 30 30 33 33 03 03 00 30 30' + '33 00 30 30 30 33 33 03 03 00 30 30 33 00 30 30' + '30 33 33 03 03 00 30 30 33 00 30 30 30 33 33 03' + '03 00 30 30 33 00 30 30 30 33 33 03 03 00 30 30' + '33 00 30 30 30 33 33 03 03 00 30 30 33 00 30 30' + '30 33 33 03 03 00 30 30 33 00 30 30 30 33 33 03' + '03 00 30 30 33 00 30 30 30 33 33 03 03 00 30 30' + '33 00 30 30 30 33 33 03 03 00 30 30 33 00 30 30' + '30 33 33 03 03 00 30 30 33 00 30 30 30 33 33 03' + '03 00 30 30 33 00 30 30 30 33 33 03 33 33 33 33' + '33 33 33 33 30 33 33 03 33 33 33 33 33 33 33 33' + '30 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + +LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US + + +TSTCODE16KBARCODE BITMAP LOADONCALL MOVEABLE DISCARDABLE IMPURE +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 00 00 00 00 00' + '00 00 00 00 00 33 33 33 30 00 30 30 03 30 03 03' + '33 33 33 33 30 00 30 30 03 30 03 03 33 33 33 33' + '30 00 30 30 03 30 03 03 33 33 33 33 30 00 30 30' + '03 30 03 03 33 33 33 33 30 00 30 30 03 30 03 03' + '33 33 33 33 30 00 00 00 00 00 00 03 33 33 33 33' + '30 30 03 03 03 00 33 03 33 33 33 33 30 30 03 03' + '03 00 33 03 33 33 33 33 30 30 03 03 03 00 33 03' + '33 33 33 33 30 30 03 03 03 00 33 03 33 33 33 33' + '30 30 03 03 03 00 33 03 33 33 33 33 30 00 00 00' + '00 00 00 03 33 33 33 33 30 03 03 33 00 03 03 03' + '33 33 33 33 30 03 03 33 00 03 03 03 33 33 33 33' + '30 03 03 33 00 03 03 03 33 33 33 33 30 03 03 33' + '00 03 03 03 33 33 33 33 30 03 03 33 00 03 03 03' + '33 33 33 00 00 00 00 00 00 00 00 00 00 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTDATAMATRIXBARCODE BITMAP LOADONCALL MOVEABLE DISCARDABLE IMPURE +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 30 00 00 00 00 00 00 00 00 00' + '03 33 30 00 00 00 00 00 00 00 00 00 03 33 30 00' + '03 30 00 00 00 03 33 33 33 33 30 00 03 30 00 00' + '00 03 33 33 33 33 30 00 03 33 33 30 00 03 33 30' + '03 33 30 00 03 33 33 30 00 03 33 30 03 33 30 03' + '30 00 00 00 00 00 00 03 33 33 30 03 30 00 00 00' + '00 00 00 03 33 33 30 03 30 03 30 00 00 00 03 30' + '03 33 30 03 30 03 30 00 00 00 03 30 03 33 30 00' + '00 03 33 30 03 30 03 33 33 33 30 00 00 03 33 30' + '03 30 03 33 33 33 30 00 00 00 00 03 33 30 03 30' + '03 33 30 00 00 00 00 03 33 30 03 30 03 33 30 00' + '00 03 33 33 33 30 03 33 33 33 30 00 00 03 33 33' + '33 30 03 33 33 33 30 00 03 33 33 30 00 03 33 30' + '03 33 30 00 03 33 33 30 00 03 33 30 03 33 30 03' + '33 33 30 00 00 03 33 33 33 33 30 03 33 33 30 00' + '00 03 33 33 33 33 30 03 33 30 03 33 33 33 33 30' + '03 33 30 03 33 30 03 33 33 33 33 30 03 33 30 03' + '30 03 30 03 30 03 30 03 33 33 30 03 30 03 30 03' + '30 03 30 03 33 33' +} + +LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL + + +TSTEXPRESSION BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 30 33 33 33 33 33 33 33 33' + '33 33 33 30 33 33 33 33 33 33 30 33 33 33 03 30' + '33 33 33 33 03 33 30 33 33 33 03 33 33 33 33 33' + '03 33 33 03 33 30 33 30 33 03 33 33 03 33 33 30' + '33 03 33 33 33 03 33 33 03 33 33 33 00 33 33 33' + '00 00 03 33 03 33 33 33 00 33 33 33 33 03 33 33' + '03 33 33 30 33 03 33 33 33 03 33 33 03 33 33 03' + '33 30 33 33 33 33 33 33 03 33 30 33 33 33 03 33' + '33 33 33 00 03 33 30 33 33 33 03 33 33 33 33 33' + '03 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTEXPRESSIONEDIT BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 7F FF FF FF FF FF FF FF FF FF' + 'FF F3 70 88 88 88 88 88 88 88 88 88 88 F3 70 FF' + 'FF FF FF FF FF FF FF FF F8 F3 70 FF FF FF FF FF' + 'CC CF 00 F0 08 F3 70 FF FF FF FF FF FC FF FF 0F' + 'F8 F3 70 FF CC FC CF CC FC CC FF 0F F8 F3 70 FC' + 'FF CF CF CF FC FF CF 0F F8 F3 70 FC FF FF FC FF' + 'FC FF CF 0F F8 F3 70 FC CC CF FC FF FC FF CF 0F' + 'F8 F3 70 FC FF CF CF CF FC FF CF 0F F8 F3 70 FF' + 'CC FC CF CC CF CC FF 0F F8 F3 70 FF FF FF FF FF' + 'FF FF FF 0F F8 F3 70 FF FF FF FF FF FF FF 00 F0' + '08 F3 70 FF FF FF FF FF FF FF FF FF F8 F3 70 00' + '00 00 00 00 00 00 00 00 00 F3 77 77 77 77 77 77' + '77 77 77 77 77 73 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTFILETOHTML BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD 0D' + 'DD 0D D0 DD 0D DD D0 D0 00 DD DD 0D DD 0D D0 DD' + '0D 00 D0 D0 DD DD DD 0D DD 0D D0 DD 00 D0 D0 D0' + 'DD DD DD 00 00 0D D0 DD 00 D0 D0 D0 DD DD DD 0D' + 'DD 0D D0 DD 00 DD 00 D0 DD DD DD 0D DD 0D 00 0D' + '0D DD D0 D0 DD DD DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD 77 77 77 77 77 DD DD DD DD DD DD DF FF' + 'FF FF FF F7 DD DD DD DD DD DD DF 0F 77 77 77 F7' + 'DD DD DD DD DD DD DF FF FF FF FF F7 DD DD DD DD' + 'DD DD DF 0F 00 00 00 F7 DD DD D4 DD DD DD DF FF' + 'FF FF FF F7 DD DD 44 4D DD DD DF 0F 00 00 00 F7' + 'DD D4 44 44 DD DD DF FF FF FF FF F7 DD 44 44 44' + '4D DD DF 0F 77 77 77 F7 DD DD 44 4D DD DD DF 0F' + '00 00 00 F7 DD DD 44 DD DD DD DF FF FF FF FF F7' + 'D4 44 44 DD DD DD DF 0F 77 77 77 F7 D4 44 DD DD' + 'DD DD DF FF FF FF FF FD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD' +} + +LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US + + +TSTMAXICODEBARCODE BITMAP LOADONCALL MOVEABLE DISCARDABLE IMPURE +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 03' + '33 03 33 03 33 33 33 33 03 33 30 00 30 00 30 00' + '33 33 33 30 00 33 33 03 33 03 33 03 33 33 33 33' + '03 33 33 33 03 33 33 33 33 33 33 03 33 33 33 30' + '00 33 33 33 33 33 30 00 33 33 33 33 03 33 33 30' + '03 33 33 03 33 33 33 03 33 33 30 03 30 03 33 33' + '33 03 30 00 33 33 03 33 33 30 33 33 30 00 33 03' + '33 33 03 30 03 30 33 33 33 03 33 33 03 30 33 03' + '30 33 03 33 03 33 33 30 00 30 33 03 30 33 03 30' + '00 33 33 33 03 33 03 30 03 30 33 33 03 33 33 33' + '33 33 03 33 33 30 33 03 33 33 33 33 33 33 30 03' + '30 03 30 00 33 33 33 33 33 33 33 30 03 33 33 03' + '33 33 33 33 03 33 33 33 33 33 03 33 03 33 33 30' + '00 33 33 33 33 30 00 30 00 33 33 33 03 33 33 33' + '33 33 03 33 03 33 33 03 33 03 33 33 33 03 33 33' + '33 03 30 00 30 00 33 33 30 00 33 33 30 00 33 03' + '33 03 33 33 33 03 33 33 33 03 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + +LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL + + +TSTNETCONNECTION BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 55 55 55 55 55 55 55 55 55 55' + '55 55 55 55 55 55 50 00 00 00 00 00 00 55 55 55' + '55 00 78 FF FF FF FF FF 87 05 55 55 55 05 78 77' + '77 77 77 77 87 75 55 55 55 05 78 88 88 88 88 88' + '87 75 55 55 55 05 78 88 88 88 88 A2 87 75 55 55' + '55 05 7F FF FF FF FF FF F7 75 55 04 44 44 57 88' + '88 88 88 88 88 75 50 07 77 77 55 77 77 77 77 77' + '77 75 50 78 F8 F8 85 55 55 55 55 55 55 55 50 80' + '00 00 00 55 55 55 55 55 55 55 55 08 FF FF F8 05' + '55 55 55 55 55 55 50 7F 7E EE EF 05 55 55 55 55' + '55 55 50 8F EF E8 6F 05 55 55 55 55 55 55 50 8F' + 'EF FE 6F 04 44 44 45 55 55 55 50 8F 77 77 7F 07' + '87 87 75 55 55 55 50 8F FF FF F8 08 FF FF 75 55' + '55 55 5C 77 77 77 70 70 00 00 75 55 55 55 5C FE' + '2C EE C0 84 FE E4 75 55 55 55 55 C2 A2 2E E0 84' + 'FF E4 75 55 55 55 55 2F 8A 22 20 87 77 74 75 55' + '55 55 55 52 2F A2 22 78 88 88 75 55 55 55 55 50' + '52 22 55 55 55 55 55 55 55 55 55 55 55 55 55 55' + '55 55 55 55 55 55' +} + + +TSTNETMESSAGE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 55 55 55 55 55 55 55 55 55 55' + '55 55 55 55 55 55 55 77 77 77 77 77 77 75 55 55' + '55 55 55 78 88 88 88 88 88 75 55 55 55 55 55 73' + '88 83 33 88 83 75 55 55 55 00 00 0B 38 30 00 38' + '38 75 55 55 55 05 55 7F F3 0F FB 03 88 75 55 55' + '55 05 55 7B 80 FB FF F0 38 75 55 04 44 44 44 78' + '0B FF FB FF 03 75 50 07 77 77 77 70 FF FB FF FB' + 'F0 75 50 78 F8 F8 8F 7F FB FF FB FF FB 05 50 80' + '00 00 00 77 77 77 77 77 77 75 55 08 FF FF F8 05' + '55 55 55 55 55 55 50 7F 7E EE EF 05 55 55 55 55' + '55 55 50 8F EF E8 6F 05 55 55 55 55 55 55 50 8F' + 'EF FE 6F 04 44 44 45 55 55 55 50 8F 77 77 7F 07' + '87 87 75 55 55 55 50 8F FF FF F8 08 FF FF 75 55' + '55 55 5C 77 77 77 70 70 00 00 75 55 55 55 5C FE' + '2C EE C0 84 FE E4 75 55 55 55 55 C2 A2 2E E0 84' + 'FF E4 75 55 55 55 55 2F 8A 22 20 87 77 74 75 55' + '55 55 55 52 2F A2 22 78 88 88 75 55 55 55 55 55' + '52 22 55 55 55 55 55 55 55 55 55 55 55 55 55 55' + '55 55 55 55 55 55' +} + + +TSTNETPERFORMANCE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD DD 91 11 B3 33 A2 22 DD DD DD' + 'DD DD DD 91 11 B3 33 A2 22 DD DD DD DD DD DD 91' + '11 B3 33 A2 22 DD DD DD DD 00 00 91 11 B3 33 A2' + '22 DD DD DD DD 0F FF 91 11 B3 33 A2 22 DD DD DD' + 'DD 0F FF 99 99 B3 33 A2 22 DD DD 04 44 44 44 0D' + 'DD B3 33 A2 22 DD D0 07 77 77 77 0D DD BB BB A2' + '22 DD D0 78 F8 F8 8F 0D DD DD DD A2 22 DD D0 80' + '00 00 00 0D DD DD DD A2 22 DD DD 08 FF FF F8 0D' + 'DD DD DD AA AA DD D0 7F 7E EE EF 0D DD DD DD DD' + 'DD DD D0 8F EF E8 6F 0D DD DD DD DD DD DD D0 8F' + 'EF FE 6F 04 44 44 4D DD DD DD D0 8F 77 77 7F 07' + '87 87 7D DD DD DD D0 8F FF FF F8 08 FF FF 7D DD' + 'DD DD DC 77 77 77 70 70 00 00 7D DD DD DD DC FE' + '2C EE C0 84 FE E4 7D DD DD DD DD C2 A2 2E E0 84' + 'FF E4 7D DD DD DD DD 2F 8A 22 20 87 77 74 7D DD' + 'DD DD DD D2 2F A2 22 78 88 88 7D DD DD DD DD DD' + 'D2 22 DD DD DD DD DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD' +} + + +TSTNVBITS BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 99' + '99 93 39 93 39 99 39 99 93 33 33 99 33 99 39 93' + '39 93 99 33 99 33 33 99 33 99 39 93 39 93 33 99' + '99 33 33 99 33 99 39 93 39 93 99 99 93 33 33 99' + '99 93 39 93 39 93 99 33 99 33 33 99 33 99 39 93' + '99 99 39 99 93 33 33 99 33 99 33 33 39 93 33 33' + '33 33 33 99 99 93 39 93 33 93 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVCOLLECTION BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '99 99 33 39 99 93 39 93 99 33 33 39 93 39 93 99' + '33 99 39 93 99 33 33 99 33 33 93 99 33 99 39 93' + '99 33 33 99 33 33 33 99 33 99 39 93 99 33 33 99' + '33 33 33 99 33 99 39 93 99 33 33 99 33 33 33 39' + '99 93 39 93 99 33 33 39 93 39 93 33 33 33 39 93' + '99 33 33 33 99 99 33 33 33 33 39 93 99 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVDICTIONARY BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 99' + '99 93 39 93 39 99 93 39 99 33 33 99 33 93 39 93' + '99 33 99 39 93 33 33 99 33 99 39 93 99 33 33 39' + '93 33 33 99 33 99 39 93 99 33 33 39 93 33 33 99' + '33 99 39 93 99 33 99 39 93 33 33 99 33 99 39 93' + '39 99 93 99 99 33 33 99 33 93 33 33 33 33 33 39' + '93 33 33 99 99 93 39 93 33 33 33 33 93 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVDQUE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 93 33 33 33 33 33 33 33 33 39' + '99 99 93 33 99 99 33 99 99 93 33 99 39 99 33 39' + '93 99 39 93 39 33 39 93 93 39 93 39 93 99 39 99' + '99 93 39 93 33 39 93 39 93 99 39 93 39 33 39 93' + '33 39 93 39 93 99 39 93 39 33 39 93 33 39 93 39' + '93 99 33 99 93 33 33 99 33 99 33 33 33 33 33 33' + '33 33 33 39 99 93 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVLARRAY BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '99 33 33 99 99 33 99 33 33 33 33 33 39 33 33 93' + '99 33 99 33 33 33 33 33 39 99 99 93 99 33 99 33' + '33 33 33 33 39 93 39 93 99 33 99 33 33 33 33 33' + '33 93 99 33 99 99 99 99 33 33 33 33 33 99 99 33' + '99 99 99 99 33 33 33 33 33 39 93 33 33 33 33 33' + '33 33 33 33 33 39 93 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVLIST BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 39' + '99 99 99 93 39 99 93 39 99 33 33 39 93 33 39 93' + '99 33 99 39 93 33 33 39 93 33 39 93 33 99 99 39' + '93 33 33 39 93 33 39 93 99 99 93 39 93 33 33 39' + '93 33 39 93 99 33 99 39 93 33 33 39 93 33 39 93' + '39 99 93 99 99 33 33 39 93 33 33 33 33 33 33 39' + '93 33 33 39 93 33 39 93 33 33 33 33 93 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVLMATRIX BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 39' + '93 93 99 33 99 99 93 99 93 33 33 39 93 93 99 39' + '93 39 93 99 33 33 33 39 93 93 99 39 93 39 93 99' + '33 33 33 39 99 39 99 33 39 99 93 99 33 33 33 39' + '99 39 99 39 93 39 93 99 33 33 33 39 99 39 99 33' + '99 99 39 99 93 33 33 39 99 39 99 33 33 33 33 99' + '33 33 33 39 99 39 99 33 33 33 33 39 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVSORTEDCOLLECTION BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 99' + '99 33 39 99 93 39 99 93 39 93 33 93 39 93 99 33' + '99 99 33 99 39 93 39 93 39 93 99 33 33 99 33 99' + '39 93 33 39 99 93 99 33 33 99 33 99 39 93 33 99' + '93 33 99 33 99 99 33 99 39 93 33 93 33 33 39 99' + '93 39 99 93 39 93 33 93 39 93 33 33 33 33 33 33' + '39 93 33 99 99 33 33 33 33 33 33 33 39 93 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTNVTREE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 39' + '93 33 99 33 39 99 99 39 99 99 33 39 93 33 99 33' + '99 33 93 99 33 93 33 39 93 33 99 33 99 99 99 99' + '99 99 33 39 93 33 99 33 99 33 93 99 33 93 33 39' + '93 33 99 99 99 33 93 99 33 93 33 39 93 33 99 99' + '39 99 33 39 99 33 33 39 93 33 33 33 33 33 33 33' + '33 33 39 99 99 99 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 FF FF FF FF FF FF FF FF 33' + '33 33 30 00 00 00 00 00 00 00 0F 33 33 33 30 F3' + '33 33 33 33 33 33 0F 33 33 33 30 F3 00 03 30 33' + '00 03 0F 33 33 33 30 F3 33 03 30 33 03 33 0F 33' + '33 33 30 F3 00 03 30 33 03 33 0F 33 33 33 30 F3' + '03 33 30 33 03 33 0F 33 33 33 30 F3 00 03 00 03' + '00 03 0F 33 33 33 30 F3 33 33 33 33 33 33 0F 33' + '33 33 30 FF FF FF FF FF FF FF 0F 33 33 33 30 00' + '00 00 00 00 00 00 03 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + +LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US + + +TSTPDF417BARCODE BITMAP LOADONCALL MOVEABLE DISCARDABLE IMPURE +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 00 30 00 30 00 03 30 03 00 00 03 03 00 30' + '00 30 00 03 30 03 00 00 03 03 00 30 00 30 00 03' + '30 03 00 00 03 03 00 30 00 03 03 30 30 00 30 30' + '03 03 00 30 00 03 03 30 30 00 30 30 03 03 00 30' + '00 03 03 30 30 00 30 30 03 03 00 30 30 33 00 30' + '00 30 00 30 03 03 00 30 30 33 00 30 00 30 00 30' + '03 03 00 30 30 33 00 30 00 30 00 30 03 03 00 30' + '30 03 03 03 00 00 03 30 03 03 00 30 30 03 03 03' + '00 00 03 30 03 03 00 30 30 03 03 03 00 00 03 30' + '03 03 00 30 00 33 00 00 30 00 33 30 03 03 00 30' + '00 33 00 00 30 00 33 30 03 03 00 30 00 33 00 00' + '30 00 33 30 03 03 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + +LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL + + +TSTPNBARCODE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD 77 77 77 77 77 77 7D DD DD DD DD' + 'DD 78 88 88 88 88 88 7D DD DD DD DD DD 73 88 83' + '33 88 83 7D DD DD DD DD DD 7B 38 30 00 38 38 7D' + 'DD DD DD DD DD 7F F3 0F FB 03 88 7D DD DD DD DD' + 'DD 7B 80 FB FF F0 38 7D DD DD DD DD DD 78 0B FF' + 'FB FF 03 7D DD DD DD DD DD 70 FF FB FF FB F0 7D' + 'DD DD DD DD DD 7F FB FF FB FF FB 0D DD DD DD DD' + 'DD 77 77 77 77 77 77 7D DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD' + 'DD DD D0 D0 D0 D0 D0 D0 D0 D0 D0 D0 D0 DD D0 D0' + 'D0 D0 D0 D0 D0 D0 D0 D0 D0 DD D0 D0 D0 D0 D0 D0' + 'D0 D0 D0 D0 D0 DD D0 D0 D0 D0 D0 D0 D0 D0 D0 D0' + 'D0 DD D0 D0 D0 D0 D0 D0 D0 D0 D0 D0 D0 DD D0 DD' + 'DD D0 D0 DD DD DD D0 DD D0 DD D0 DD DD D0 D0 DD' + 'DD DD D0 DD D0 DD D0 DD DD D0 D0 DD DD DD D0 DD' + 'D0 DD D0 DD DD D0 D0 DD DD DD D0 DD D0 DD DD DD' + 'DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD' +} + + +TSTREGEX BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 30 00 03 33 33 33' + '33 33 33 30 00 03 30 33 33 33 33 33 33 33 33 33' + '33 03 30 33 33 33 33 33 33 33 33 33 33 03 30 33' + '33 33 30 00 03 33 00 00 33 03 30 33 33 33 30 33' + '03 33 30 33 33 03 30 33 33 33 33 00 03 00 30 33' + '33 03 30 33 33 33 33 33 03 33 33 03 33 03 30 33' + '33 33 30 00 03 33 00 00 33 03 30 33 33 33 33 33' + '33 33 33 33 33 03 30 33 33 33 33 33 33 33 33 33' + '33 03 30 33 33 33 33 33 33 33 33 33 33 03 30 33' + '30 33 30 33 33 33 33 33 33 03 30 33 33 03 03 33' + '33 33 33 33 33 03 30 33 33 30 33 33 33 33 33 33' + '33 03 30 00 03 33 33 33 33 33 33 30 00 03 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTSPAWNAPPLICATION BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 DD DD DD DD DD DD DD DD DD DD' + 'DD DD D0 00 00 00 00 00 00 0D DD DD DD DD D0 B8' + 'B8 B8 B8 B8 B8 0D DD DD DD DD D0 8C CC CB 8C CC' + 'CB 0D DD DD DD DD D0 B8 B8 B8 B8 B8 B8 0D DD DD' + 'DD DD D0 8C CC CB 8C CC CB 0D 77 77 77 DD D0 B8' + 'B8 B8 B8 B8 B8 00 00 00 07 7D D0 00 00 00 00 00' + '00 0D DD DD D0 7D D0 80 44 44 44 08 08 0D DD DD' + 'D0 7D D0 00 00 00 00 00 00 0D DD DD D0 7D DD DD' + 'DD DD DD DD DD DD DD DD D0 7D DD DD DD DD DD DD' + 'DD DD DD DD D0 7D D0 00 00 00 00 00 00 0D DD DD' + 'D0 7D D0 B8 B8 B8 B8 B8 B8 0D DD DD D0 7D D0 8C' + 'CC CB 8C CC CB 0D DD D7 D0 7D D0 B8 B8 B8 B8 B8' + 'B8 0D DD 07 D0 7D D0 8C CC CB 8C CC CB 0D D0 07' + '70 DD D0 B8 B8 B8 B8 B8 B8 0D 00 00 0D DD D0 8C' + 'CC CB 8C CC CB 0D D0 07 DD DD D0 B8 B8 B8 B8 B8' + 'B8 0D DD 0D DD DD D0 00 00 00 00 00 00 0D DD DD' + 'DD DD D0 80 44 44 44 08 08 0D DD DD DD DD D0 00' + '00 00 00 00 00 0D DD DD DD DD DD DD DD DD DD DD' + 'DD DD DD DD DD DD' +} + + +TSTVERSIONINFO BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 88 88 88 88 88 88 88 88 88 88' + '88 88 88 88 88 88 80 00 88 08 00 80 00 08 88 88' + '88 88 80 80 88 08 00 88 08 88 88 88 88 88 80 80' + '88 08 88 88 80 88 88 88 88 88 80 80 88 08 88 88' + '88 08 88 88 88 88 80 80 80 08 88 80 88 08 88 88' + '88 88 88 88 88 08 88 88 00 08 88 88 88 88 88 88' + '88 88 88 88 88 88 88 88 80 00 00 08 88 88 88 88' + '88 88 88 88 80 BF BF 00 00 00 88 88 88 88 88 88' + '80 FB FB 0F FF F0 88 88 88 88 88 88 80 BF BF 0F' + 'FF F0 88 88 88 88 88 80 00 FB 00 0F FF F0 88 88' + '88 88 88 80 B0 BF 0F 0F FF F0 88 88 88 88 88 80' + 'F0 00 00 FF FF F0 88 88 88 88 88 80 BF BF 0F FF' + 'FF F0 88 88 88 88 80 00 FB 00 0F FF FF F0 88 88' + '88 88 80 B0 BF 0F 0F FF 00 00 88 88 88 88 80 F0' + '00 00 FF FF 0F 08 88 88 88 88 80 BF BF 0F FF FF' + '00 88 88 88 88 88 80 FB 00 00 00 00 08 88 88 88' + '88 88 80 BF 0F 08 88 88 88 88 88 88 88 88 80 00' + '00 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88' + '88 88 88 88 88 88' +} + + +TSTWMDATACOPY BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 44 44 44 44 43 33 33' + '33 33 33 33 33 4F FF FF FF 43 33 33 33 33 33 33' + '33 4F 00 00 0F 43 33 33 33 33 00 00 00 4F FF FF' + 'FF 43 33 33 33 33 0F FF FF 4F 00 00 0F 43 33 33' + '33 33 0F 00 00 4F FF FF FF 43 33 33 33 33 0F FF' + 'FF 4F 00 F4 44 43 33 33 33 33 0F 00 00 4F FF F4' + 'F4 33 33 33 33 33 0F FF FF 4F FF F4 43 33 33 33' + '33 33 0F 00 F0 44 44 44 33 33 33 33 33 33 0F FF' + 'F0 F0 33 33 33 33 33 33 33 33 0F FF F0 03 33 33' + '33 33 33 33 33 33 00 00 00 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 03 03 30 30 30' + '33 33 33 33 33 33 33 03 03 30 30 30 33 33 33 33' + '33 33 33 03 03 30 30 30 33 33 33 33 33 33 30 30' + '30 30 03 00 33 33 33 33 33 33 30 30 30 30 03 00' + '33 33 33 33 33 33 30 30 30 30 33 30 33 33 33 33' + '33 33 30 30 30 30 33 30 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + + +TSTGENERALLOG BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 88 88 88 88 88 88 88 88 88 88' + '88 88 8B 08 88 88 88 84 44 88 88 88 88 88 80 00' + '88 88 88 48 88 48 44 48 48 48 88 00 08 88 88 48' + '88 48 48 88 48 48 88 80 80 88 88 48 84 48 44 48' + '48 48 88 88 0B 08 88 48 88 88 48 48 44 88 88 88' + '80 70 88 48 88 48 44 48 48 88 88 88 88 0B 08 84' + '44 88 88 88 88 88 88 88 88 80 78 88 88 88 88 88' + '88 88 00 00 88 88 80 00 00 88 88 80 00 00 11 11' + '70 00 01 11 11 00 00 71 11 10 1F F8 11 11 11 77' + '71 11 11 18 88 10 1F FF FF FF FF F7 FF FF FF FF' + 'FF 10 1F FF FF FF FF F7 FF FF FF FF F1 08 81 FF' + 'FF FF FF F7 FF FF FF FF F1 08 81 FF FF FF FF F7' + 'FF FF FF FF F1 08 81 0F FF FF F0 F7 FF FF FF FF' + '11 08 81 FF 0F 00 0F F7 FF FF FF FF 10 88 88 10' + 'FF FF FF 07 FF FF FF FF 10 88 88 1F F0 F0 FF F7' + 'FF FF FF FF 10 88 88 1F 0F FF F0 F7 FF FF FF FF' + '10 88 88 1F FF 0F FF F7 FF FF FF F1 08 88 88 87' + '77 77 77 77 77 77 77 77 88 88 88 88 88 88 88 88' + '88 88 88 88 88 88' +} + + +TSTNTEVENTLOG BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 88 88 88 88 88 88 88 88 88 88' + '88 88 8B 08 88 88 88 44 48 44 48 84 44 88 80 00' + '88 88 88 84 88 84 88 88 48 88 88 00 08 88 88 84' + '88 44 88 88 48 88 88 80 80 88 88 84 84 84 88 88' + '48 88 88 88 0B 08 88 84 84 84 88 88 48 88 88 88' + '80 70 88 84 48 84 88 48 48 48 88 88 88 0B 08 44' + '48 44 48 44 44 48 88 88 88 80 78 88 88 88 88 88' + '88 88 00 00 88 88 80 00 00 88 88 80 00 00 11 11' + '70 00 01 11 11 00 00 71 11 10 1F F8 11 11 11 77' + '71 11 11 18 88 10 1F FF FF FF FF F7 FF FF FF FF' + 'FF 10 1F FF FF FF FF F7 FF FF FF FF F1 08 81 FF' + 'FF FF FF F7 FF FF FF FF F1 08 81 FF FF FF FF F7' + 'FF FF FF FF F1 08 81 0F FF FF F0 F7 FF FF FF FF' + '11 08 81 FF 0F 00 0F F7 FF FF FF FF 10 88 88 10' + 'FF FF FF 07 FF FF FF FF 10 88 88 1F F0 F0 FF F7' + 'FF FF FF FF 10 88 88 1F 0F FF F0 F7 FF FF FF FF' + '10 88 88 1F FF 0F FF F7 FF FF FF F1 08 88 88 87' + '77 77 77 77 77 77 77 77 88 88 88 88 88 88 88 88' + '88 88 88 88 88 88' +} + + +TSTEXCEPTIONLOG BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 88 88 88 88 88 88 88 88 88 88' + '88 88 8B 08 88 88 88 88 88 8B 0B 88 88 88 80 00' + '88 88 88 88 8B B0 00 BB 88 88 88 00 08 88 88 88' + '8B BB BB BB 88 88 88 80 80 88 88 88 BB BB 0B BB' + 'B8 88 88 88 0B 08 88 88 BB BB 0B BB B8 88 88 88' + '80 70 88 88 BB B0 00 BB B8 88 88 88 88 0B 08 88' + '8B B0 00 BB 88 88 88 88 88 80 78 88 8B B0 00 BB' + '88 88 00 00 88 88 80 00 88 8B BB 88 88 00 11 11' + '70 00 01 11 11 00 00 71 11 10 1F F8 11 11 11 77' + '71 11 11 18 88 10 1F FF FF FF FF F7 FF FF FF FF' + 'FF 10 1F FF FF FF FF F7 FF FF FF FF F1 08 81 FF' + 'FF FF FF F7 FF FF FF FF F1 08 81 FF FF FF FF F7' + 'FF FF FF FF F1 08 81 0F FF FF F0 F7 FF FF FF FF' + '11 08 81 FF 0F 00 0F F7 FF FF FF FF 10 88 88 10' + 'FF FF FF 07 FF FF FF FF 10 88 88 1F F0 F0 FF F7' + 'FF FF FF FF 10 88 88 1F 0F FF F0 F7 FF FF FF FF' + '10 88 88 1F FF 0F FF F7 FF FF FF F1 08 88 88 87' + '77 77 77 77 77 77 77 77 88 88 88 88 88 88 88 88' + '88 88 88 88 88 88' +} + diff --git a/components/systools/source/design/StRegDb.pas b/components/systools/source/design/StRegDb.pas new file mode 100644 index 000000000..d64bf07c5 --- /dev/null +++ b/components/systools/source/design/StRegDb.pas @@ -0,0 +1,67 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StRegDb.pas 4.04 *} +{*********************************************************} +{* SysTools: Data-Aware Component Registration Unit *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} +//{$I StDefine.inc} + +{$R StRegDb.r32} + +unit StRegDb; + +interface + +uses + Classes; + +procedure Register; + +implementation + +uses + StBase, + StDbBarC, + StDbPNBC, + StDb2DBC; +//, StExport; + +procedure Register; +begin + RegisterComponents('SysTools', [ + TStDbBarCode, + TStDbPNBarCode, + TStDbPDF417Barcode, + TStDbMaxiCodeBarcode + ]); +end; + +end. diff --git a/components/systools/source/design/StRegDb.rc b/components/systools/source/design/StRegDb.rc new file mode 100644 index 000000000..e5d2184f3 --- /dev/null +++ b/components/systools/source/design/StRegDb.rc @@ -0,0 +1,193 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ +/**************************************************************************** + + +stregdb.rc + +produced by Borland Resource Workshop + + +*****************************************************************************/ + + +STDBTEMPLATE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 77 77 77 77 77 77 77 73 33 33 33 33 78 7F' + 'FF F8 FF FF FF 73 33 33 33 33 7F 7F 88 F8 F8 88' + '8F 73 33 33 33 33 78 7F FF F8 FF FF FF 73 33 33' + '33 33 7F 7F 88 F8 F8 88 FF 73 33 33 33 33 78 7F' + 'FF F8 FF FF FF 73 33 33 33 33 7F 7F 88 F8 F8 88' + '8F 73 33 33 33 33 78 7F FF F8 FF FF FF 73 33 33' + '33 33 77 77 77 77 77 77 77 73 33 33 33 33 78 7F' + '88 88 F8 88 88 73 33 33 33 33 77 77 77 77 77 77' + '77 73 33 33 33 33' +} + + +TSTDBBARCODE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 33 03 33 33 33 33 33 33 33 33' + '30 33 33 03 33 33 33 33 33 33 33 33 30 33 33 03' + '03 00 30 30 33 00 30 30 30 33 33 03 03 00 30 30' + '33 00 30 30 30 33 33 03 03 00 30 30 33 00 30 30' + '30 33 33 03 03 00 30 30 33 00 30 30 30 33 33 03' + '03 00 30 30 33 00 30 30 30 33 33 03 03 00 30 30' + '33 00 30 30 30 33 33 03 03 00 30 30 33 00 30 30' + '30 33 77 07 07 00 70 70 77 00 30 30 30 33 78 0F' + '0F 00 F0 F0 FF 00 30 30 30 33 7F 0F 08 00 F0 80' + '8F 00 30 30 30 33 78 0F 0F 00 F0 F0 FF 00 30 30' + '30 33 7F 0F 08 00 F0 80 FF 00 30 30 30 33 78 0F' + '0F 00 F0 F0 FF 00 30 30 30 33 7F 0F 88 F8 F8 88' + '8F 73 33 33 30 33 78 0F FF F8 FF FF FF 73 33 33' + '30 33 77 77 77 77 77 77 77 73 33 33 33 33 78 7F' + '88 88 F8 88 88 73 33 33 33 33 77 77 77 77 77 77' + '77 73 33 33 33 33' +} + +LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US + + +TSTDBMAXICODEBARCODE BITMAP LOADONCALL MOVEABLE DISCARDABLE IMPURE +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33 03 33 03 33 33 33 30 33 33 33' + '33 30 00 30 00 33 33 33 00 03 33 33 33 33 03 33' + '03 33 33 33 30 33 33 33 33 03 33 33 33 33 33 03' + '33 33 33 33 30 00 33 33 30 03 30 00 33 33 33 33' + '33 03 33 30 03 30 03 03 30 33 77 77 77 77 77 07' + '77 77 70 33 00 03 7F 7F FF FF F7 0F F0 0F 70 33' + '30 33 7F 7F 88 88 F0 F8 08 80 73 03 33 33 7F 7F' + 'FF 0F F0 FF 0F F0 73 03 33 03 7F 7F 80 00 F7 08' + '80 0F 70 33 30 00 7F 7F FF 0F F7 0F FF FF 70 33' + '33 03 7F 7F 88 88 07 F0 08 80 03 33 03 33 7F 7F' + 'FF F0 00 FF F0 0F 73 30 00 33 7F 7F 88 88 07 F8' + '88 8F 73 33 03 33 7F 7F FF 0F F7 FF FF 0F 73 03' + '33 03 7F 7F 80 00 F7 F8 80 00 70 00 30 00 7F 7F' + 'FF 0F F7 FF FF 0F 73 03 33 03 7F 7F 88 88 F7 F8' + '88 8F 73 33 33 33 7F 7F FF FF F7 FF FF FF 73 33' + '33 33 77 77 77 77 77 77 77 77 73 33 33 33 7F 7F' + 'FF FF FF FF FF FF 73 33 33 33 77 77 77 77 77 77' + '77 77 73 33 33 33' +} + + +TSTDBPDF417BARCODE BITMAP LOADONCALL MOVEABLE DISCARDABLE IMPURE +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 30 03 00 03 00 00 33 00 30 00 00 30 30 03' + '00 03 00 00 33 00 30 00 00 30 30 03 00 03 00 00' + '33 00 30 00 00 30 30 03 00 00 30 33 03 00 03 03' + '00 30 30 03 00 00 30 33 03 00 03 03 00 30 30 03' + '00 00 30 33 03 00 03 03 00 30 30 03 03 03 30 03' + '00 03 00 03 00 30 30 03 03 03 30 03 00 03 00 03' + '00 30 70 07 07 07 70 07 00 07 00 03 00 30 70 0F' + '0F 00 70 F0 F0 00 00 33 00 30 70 0F 08 00 70 80' + '80 00 00 33 00 30 70 0F 0F 00 70 F0 F0 00 00 33' + '00 30 70 0F 00 0F 70 00 0F 00 03 33 00 30 70 0F' + '00 0F 70 00 08 00 03 33 00 30 70 0F 00 0F 70 00' + '0F 00 03 33 00 30 7F 7F 88 8F 7F 88 88 F7 33 33' + '33 33 7F 7F FF FF 7F FF FF F7 33 33 33 33 7F 7F' + '88 8F 7F 88 88 F7 33 33 33 33 7F 7F FF FF 7F FF' + 'FF F7 33 33 33 33 77 77 77 77 77 77 77 77 33 33' + '33 33 7F 7F FF FF FF FF FF F7 33 33 33 33 77 77' + '77 77 77 77 77 77 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 33' +} + +LANGUAGE LANG_NEUTRAL,SUBLANG_NEUTRAL + + +TSTDBPNBARCODE BITMAP +{ + '42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00' + '00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00' + '00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00' + '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80' + '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80' + '00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF' + '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF' + '00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33' + '33 33 33 33 33 77 77 77 77 77 77 73 33 33 33 33' + '33 78 88 88 88 88 88 73 33 33 33 33 33 73 88 83' + '33 88 83 73 33 33 33 33 33 7B 38 30 00 38 38 73' + '33 33 33 33 33 7F F3 0F FB 03 88 73 33 33 33 33' + '33 7B 80 FB FF F0 38 73 33 33 33 33 33 78 0B FF' + 'FB FF 03 73 33 33 33 33 33 70 FF FB FF FB F0 73' + '33 33 33 33 33 7F FB FF FB FF FB 03 33 33 33 33' + '33 77 77 77 77 77 77 73 33 33 30 30 30 30 30 30' + '30 30 30 30 30 33 30 30 30 30 30 30 30 30 30 30' + '30 33 70 70 70 70 70 70 70 70 30 30 30 33 70 70' + 'F0 F0 F0 F0 F0 70 30 30 30 33 70 70 80 F0 F0 80' + '80 70 30 30 30 33 70 70 F0 F0 F0 F0 F0 70 30 30' + '30 33 7F 7F 80 F0 F8 88 FF 70 33 33 30 33 78 7F' + 'F0 F0 FF FF FF 70 33 33 30 33 7F 7F 80 F0 F8 88' + '8F 70 33 33 30 33 78 7F F0 F0 FF FF FF 70 33 33' + '30 33 77 77 70 70 77 77 77 70 33 33 30 33 78 7F' + '88 88 F8 88 88 73 33 33 33 33 77 77 77 77 77 77' + '77 73 33 33 33 33' +} + diff --git a/components/systools/source/design/streg.r32 b/components/systools/source/design/streg.r32 new file mode 100644 index 000000000..4c6ca20f4 Binary files /dev/null and b/components/systools/source/design/streg.r32 differ diff --git a/components/systools/source/design/stregdb.r32 b/components/systools/source/design/stregdb.r32 new file mode 100644 index 000000000..4fff181fc Binary files /dev/null and b/components/systools/source/design/stregdb.r32 differ diff --git a/components/systools/source/include/StDefine.inc b/components/systools/source/include/StDefine.inc new file mode 100644 index 000000000..fde61aeeb --- /dev/null +++ b/components/systools/source/include/StDefine.inc @@ -0,0 +1,233 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDefine.inc 4.03 *} +{*********************************************************} +{* SysTools: Compiler options/directives include file *} +{*********************************************************} + +{ Because StDefine.inc is included in all SysTools units, you can specify } +{ global compiler options here. STDEFINE is included *before* each units' } +{ required compiler options, so options specified here might be overridden } +{ by hardcoded options in the source file. } + +{$IFNDEF LINUX} +{---Global compiler defines for 32-bit OS's---} +{$A+} {Word Align Data} +{$H+} {Huge string support} +{$Q+} {Overflow check} +{$R+} {Range check} +{$S-} {Stack check} +{$T-} {Typed @ check} +{$V-} {Var strings} +{$B-} {Incomplete boolean evaluation} +{$J+} {Writeable Typed Constants} +{$ENDIF LINUX} + +{$DEFINE ThreadSafe} +{ This define determines whether SysTools operations are safe in a 32-bit } +{ multi-threaded application. Leaving it undefined will improved performance} +{ slightly in a single-threaded 32-bit application. } + +{$DEFINE Median} +{.$DEFINE MidPoint} +{.$DEFINE Random} +{ The three partitioning methods used by the merge sort algorithm in STSORT.} +{ Choose one, and one only. Median is on average fastest, and quite safe. } +{ Midpoint is the simplest, but may degrade on some data sets. Random is } +{ the safest, but on average the slowest. Safety in this context means the } +{ prevention of the underlying quicksort degenerating into a sort of O(N^2) } +{ The default is Median. } + +{.$DEFINE SuppressWarnings} +{ This define enables you to suppress warnings that are generated for code } +{ in SysTools by Delphi 2/3. The two most common warnings are (a) function } +{ does not set Result and (b) variable used before being initialized. The } +{ code however has been tested to be correct but is complex enough to fool } +{ the compiler. You should leave this define activated. } + +{.$DEFINE UseMathUnit} +{ This define is used to decide if the Math unit should be used. } +{ Define UseMathUnit if the Math unit is available (it isn't with some } +{ versions of the compilers -- Delphi 1, C++Builder 1, Delphi 2 Standard, } +{ and a few others - check to be sure). } + +{$IFDEF FPC} + {$UNDEF VER80} + {$UNDEF VER90} + {$UNDEF VER93} + {$UNDEF VER100} + {$UNDEF VER110} + {$UNDEF VER120} + {$UNDEF VER125} + {$UNDEF VER130} + {$UNDEF VER135} + {$UNDEF VER140} + + {$DEFINE DELPHIXE2} + + {$DEFINE HasLongWord} + {$DEFINE HasInt64} +{$ENDIF} + + +{===========!! DO NOT ALTER ANYTHING BEYOND THIS POINT !!==================} +{===========!! DO NOT ALTER ANYTHING BEYOND THIS POINT !!==================} + +{$IFDEF VER93} + {$DEFINE CBuilder} +{$ENDIF} +{$IFDEF VER110} + {$DEFINE CBuilder} + {$ObjExportAll On} +{$ENDIF} +{$IFDEF VER125} + {$DEFINE CBuilder} + {$ObjExportAll On} +{$ENDIF} +{$IFDEF VER130} + {$IFDEF BCB} + {$DEFINE CBuilder} + {$ObjExportAll On} + {$ENDIF} +{$ENDIF} +{$IFDEF VER140} + {$IFDEF BCB} + {$DEFINE CBuilder} + {$ObjExportAll On} + {$ENDIF} +{$ENDIF} + +{$IFNDEF LINUX} + {$IFNDEF WIN32} + {$IFDEF VER80} + {$DEFINE WIN16} { Delphi 1.0, 16-Bit Windows } + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFNDEF VER80} {Delphi 1.0} + {$DEFINE VERSION2} {Delphi 2.0 and BCB 1 or higher} +{$ENDIF} + +{$IFDEF VERSION2} + {$IFNDEF VER90} {Delphi 2.0} + {$IFNDEF VER93} {BCB 1.0} + {$DEFINE VERSION3} {Delphi 3.0 or BCB 3.0} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VERSION3} + {$IFNDEF VER100} {Delphi 3} + {$IFNDEF VER110} {BCB 3} + {$DEFINE VERSION4} {Delphi 4.0 or higher} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VERSION4} + {$IFNDEF VER120} {Delphi 4} + {$IFNDEF VER125} {BCB 4} + {$DEFINE VERSION5} {Delphi 5.0 or higher} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VERSION5} + {$IFNDEF VER130} { Delphi 5 } + {$IFNDEF VER135} { BCB 5 } + {$IFNDEF LINUX } + {$DEFINE VERSION6} { Delphi 6.0 or higher } + {$ENDIF} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VERSION6} + {$IFNDEF VER140} { Delphi 6 } + {$IFNDEF LINUX } + {$DEFINE VERSION7} { Delphi 7.0 or higher } + {$ENDIF} + {$ENDIF} +{$ENDIF} + +(* +{$IF compilerversion >= 23} { Delphi XE2 } + {$DEFINE DELPHIXE2} +{$IFEND} +*) + +{$IFDEF VERSION4} + {$DEFINE HasLongWord} { D4 and above have a true LongWord type } + {$DEFINE HasInt64 } { D4 and above have a 64-bit Integer } +{$ENDIF} +{$IFDEF LINUX} + {$DEFINE HasLongWord} { Kylix has a true LongWord type } + {$DEFINE HasInt64 } { Kylix has a 64-bit Integer } +{$ENDIF} + +{$IFDEF VERSION3} + {$IFNDEF VERSION4} + {$DEFINE VERSION3ONLY} + {$ENDIF} +{$ENDIF} + + +{Set up the string type expected} +{$UNDEF HStrings} +{$UNDEF WStrings} + +{$IFOPT H+} + {$DEFINE HStrings} {Huge strings under WIN32} + {$UNDEF NStrings} +{$ELSE} + {$DEFINE WStrings} {255-character strings under WIN32} + {$UNDEF NStrings} +{$ENDIF} + +{$IFDEF Median} + {$IFDEF MidPoint} + !! ERROR: you must define only one of Median, MidPoint, Random + {$ENDIF} + {$IFDEF Random} + !! ERROR: you must define only one of Median, MidPoint, Random + {$ENDIF} +{$ENDIF} +{$IFDEF MidPoint} + {$IFDEF Random} + !! ERROR: you must define only one of Median, MidPoint, Random + {$ENDIF} +{$ENDIF} +{$IFNDEF Median} + {$IFNDEF MidPoint} + {$IFNDEF Random} + !! ERROR: you must define at least one of Median, MidPoint, Random + {$ENDIF} + {$ENDIF} +{$ENDIF} + + diff --git a/components/systools/source/run/StBase.pas b/components/systools/source/run/StBase.pas new file mode 100644 index 000000000..f38c81a1c --- /dev/null +++ b/components/systools/source/run/StBase.pas @@ -0,0 +1,1520 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StBase.pas 4.04 *} +{*********************************************************} +{* SysTools: Base unit for SysTools *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +unit StBase; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, + {$ENDIF} + Classes, SysUtils, StdCtrls, + + StConst; + +const +{.Z+} + StMaxBlockSize = MaxLongInt; +{.Z-} + +type +{!!.01 - moved from StBase.pas } + TStLineTerminator = ( {possible line terminators...} + ltNone, {..no terminator, ie fixed length lines} + ltCR, {..carriage return (#13)} + ltLF, {..line feed (#10)} + ltCRLF, {..carriage return/line feed (#13/#10)} + ltOther); {..another character} +{!!.01 - end moved } + +type +{$IFDEF CBuilder} + TStHwnd = Integer; +{$ELSE} + TStHwnd = HWND; +{$ENDIF} + +{-SysTools exception class tree} +type + EStException = class(Exception) {ancestor to all SysTools exceptions} + protected {private} + FErrorCode : Longint; + + public + constructor CreateResTP(Ident : LongInt; Dummy : Word); + constructor CreateResFmtTP(Ident : Longint; const Args : array of const; + Dummy : Word); + property ErrorCode : LongInt + read FErrorCode + write FErrorCode; + end; + EStExceptionClass = class of EStException; + + EStContainerError = class(EStException); {container exceptions} + EStSortError = class(EStException); {sorting exceptions} + EStRegIniError = class(EStException); {registry/INI file exceptions} + EStBCDError = class(EStException); {Bcd exceptions} + EStStringError = class(EStException); {String class exceptions} + EStVersionInfoError = class(EStException); {Version info exception} + EStNetException = class(EStException); {Network exception} + EStBarCodeError = class(EStException); {BarCode exception} + EStPNBarCodeError = class(EStException); {PostNet BarCode exception} + EStStatError = class(EStException); {statistics exceptions} + EStFinError = class(EStException); {Financial exceptions} + EStMimeError = class(EStException); {Mime exceptions} + EStToHTMLError = class(EStException); {ToHTML exceptions} + EStSpawnError = class(EStException); {SpawnApplication errors} + EStMMFileError = class(EStException); {MemoryMappedFile errors} + EStBufStreamError =class(EStException); {Buffered stream errors} + EStRegExError = class(EStException); {RegEx errors} + EStDecMathError = class(EStException); {Decimal math errors} + EStPRNGError = class(EStException); {Random number errors} + + EStExprError = class(EStException) {expression evaluator exceptions} + protected {private} + FErrorCol : Integer; + public + constructor CreateResTPCol(Ident : Longint; Column : Integer; Dummy : Integer); + property ErrorColumn : Integer + {-Returns the string position at the start of the token where + the error was detected} + read FErrorCol; + end; + + +const +{.Z+} + StMaxFileLen = 260; + + StRLEMaxCount = 127; { Used by RLE } + StRLERunMode = $80; { Used by RLE } +{.Z-} + +const +{.Z+} + {used by CompareLetterSets for estimating word similarity} + StLetterValues : array['A'..'Z'] of Byte = ( + 3 {A} , 6 {B} , 5 {C} , 4 {D} , 3 {E} , 5 {F} , 5 {G} , 4 {H} , 3 {I} , + 8 {J} , 7 {K} , 4 {L} , 5 {M} , 3 {N} , 3 {O} , 5 {P} , 7 {Q} , 4 {R} , + 3 {S} , 3 {T} , 4 {U} , 6 {V} , 5 {W} , 8 {X} , 8 {Y} , 9 {Z} ); + + StHexDigits : array[0..$F] of AnsiChar = '0123456789ABCDEF'; + DosDelimSet : set of AnsiChar = ['\', ':', #0]; +{$IFDEF VERSION4} { Delphi/Builder 3 doesn't like widestring typed constants } + StHexDigitsW : WideString = '0123456789ABCDEF'; + DosDelimSetW : WideString = '\:'; +{$ENDIF} + +{.Z-} + +type +{.Z+} + TSmallArrayA = array[0..StMaxFileLen-1] of AnsiChar; + TSmallArray = array[0..StMaxFileLen-1] of Char; + BTable = array[0..255] of Byte; {Table used by Boyer-Moore search routines} + {$IFDEF UNICODE} + BTableU = array[0..$FFFF] of Byte; + {$ENDIF} +{.Z-} + +type +{.Z+} + PDouble = ^Double; + TDoubleArray = array[0..(stMaxBlockSize div SizeOf(Double))-1] of Double; + PDoubleArray = ^TDoubleArray; + TIntArray = array[0..(StMaxBlockSize div SizeOf(Integer))-1] of Integer; + PIntArray = ^TIntArray; +{.Z-} + +type + {the SysTools floating point type} + {$IFOPT N+} + TStFloat = Extended; + {$ELSE} + TStFloat = Real; + {$ENDIF} + +const + WMCOPYID : DWORD = $AFAF; + +type + TStNode = class(TPersistent) +{.Z+} + protected {private} + FData : Pointer; +{.Z-} + public + constructor Create(AData : Pointer); + virtual; + property Data : Pointer + read FData + write FData; + end; + +{.Z+} + TStNodeClass = class of TStNode; +{.Z-} + + TStContainer = class; + + TCompareFunc = + function(Data1, Data2 : Pointer) : Integer; + TStCompareEvent = + procedure(Sender : TObject; Data1, Data2 : Pointer; var Compare : Integer) + of object; + + TDisposeDataProc = + procedure(Data : Pointer); + TStDisposeDataEvent = + procedure(Sender : TObject; Data : Pointer) + of object; + + TLoadDataFunc = + function(Reader : TReader) : Pointer; + TStLoadDataEvent = + procedure(Sender : TObject; Reader : TReader; var Data : Pointer) + of object; + + TStoreDataProc = + procedure(Writer : TWriter; Data : Pointer); + TStStoreDataEvent = + procedure(Sender : TObject; Writer : TWriter; Data : Pointer) + of object; + + TStringCompareFunc = + function(const String1, String2 : string) : Integer; + TStStringCompareEvent = + procedure(Sender : TObject; const String1, String2 : string; var Compare : Integer) + of object; + + TUntypedCompareFunc = + function(const El1, El2) : Integer; + TStUntypedCompareEvent = + procedure(Sender : TObject; const El1, El2; var Compare : Integer) + of object; + + TIterateFunc = + function(Container : TStContainer; Node : TStNode; OtherData : Pointer) : Boolean; + TIteratePointerFunc = + function(Container : TStContainer; Data, OtherData : Pointer) : Boolean; + TIterateUntypedFunc = + function(Container : TStContainer; var Data; OtherData : Pointer) : Boolean; + + TStContainer = class(TPersistent) + {.Z+} + protected {private} + {property instance variables} + FCompare : TCompareFunc; + FDisposeData : TDisposeDataProc; + FLoadData : TLoadDataFunc; + FStoreData : TStoreDataProc; + + {event variables} + FOnCompare : TStCompareEvent; + FOnDisposeData : TStDisposeDataEvent; + FOnLoadData : TStLoadDataEvent; + FOnStoreData : TStStoreDataEvent; + + {private instance variables} + {$IFDEF ThreadSafe} + conThreadSafe : TRTLCriticalSection; + {$ENDIF} + + procedure SetCompare(C : TCompareFunc); + procedure SetDisposeData(D : TDisposeDataProc); + procedure SetLoadData(L : TLoadDataFunc); + procedure SetStoreData(S : TStoreDataProc); + + protected + conNodeClass : TStNodeClass; + conNodeProt : Integer; + FCount : Longint; + + {protected undocumented methods} + function AssignPointers(Source : TPersistent; AssignData : TIteratePointerFunc) : boolean; + function AssignUntypedVars(Source : TPersistent; AssignData : TIterateUntypedFunc) : boolean; + procedure ForEachPointer(Action : TIteratePointerFunc; OtherData : Pointer); + virtual; + procedure ForEachUntypedVar(Action : TIterateUntypedFunc; OtherData : pointer); + virtual; + procedure GetArraySizes(var RowCount, ColCount, ElSize : Cardinal); + virtual; + procedure SetArraySizes(RowCount, ColCount, ElSize : Cardinal); + virtual; + function StoresPointers : boolean; + virtual; + function StoresUntypedVars : boolean; + virtual; + + {protected documented} + procedure IncNodeProtection; + {-Prevent container Destroy from destroying its nodes} + procedure DecNodeProtection; + {-Allow container Destroy to destroy its nodes} + procedure EnterCS; + {-Enter critical section for this instance} + procedure LeaveCS; + {-Leave critical section for this instance} + {.Z-} + public + constructor CreateContainer(NodeClass : TStNodeClass; Dummy : Integer); + {-Create an abstract container (called by descendants)} + destructor Destroy; + override; + {-Destroy a collection, and perhaps its nodes} + procedure Clear; + virtual; abstract; + {-Remove all elements from collection} + procedure DisposeNodeData(P : TStNode); + {-Destroy the data associated with a node} + + {wrapper methods for using events or proc/func pointers} + function DoCompare(Data1, Data2 : Pointer) : Integer; + virtual; + procedure DoDisposeData(Data : Pointer); + virtual; + function DoLoadData(Reader : TReader) : Pointer; + virtual; + procedure DoStoreData(Writer : TWriter; Data : Pointer); + virtual; + + procedure LoadFromFile(const FileName : string); + dynamic; + {-Create a container and its data from a file} + procedure LoadFromStream(S : TStream); + dynamic; abstract; + {-Create a container and its data from a stream} + procedure StoreToFile(const FileName : string); + dynamic; + {-Create a container and its data from a file} + procedure StoreToStream(S : TStream); + dynamic; abstract; + {-Write a container and its data to a stream} + + property Count : LongInt + {-Return the number of elements in the collection} + read FCount; + + property Compare : TCompareFunc + {-Set or read the node comparison function} + read FCompare + write SetCompare; + + property DisposeData : TDisposeDataProc + {-Set or read the node data dispose function} + read FDisposeData + write SetDisposeData; + + property LoadData : TLoadDataFunc + {-Set or read the node data load function} + read FLoadData + write SetLoadData; + + property StoreData : TStoreDataProc + {-Set or read the node data load function} + read FStoreData + write SetStoreData; + + {events} + property OnCompare : TStCompareEvent + read FOnCompare + write FOnCompare; + + property OnDisposeData : TStDisposeDataEvent + read FOnDisposeData + write FOnDisposeData; + + property OnLoadData : TStLoadDataEvent + read FOnLoadData + write FOnLoadData; + + property OnStoreData : TStStoreDataEvent + read FOnStoreData + write FOnStoreData; + end; + + TAssignRowData = record + RowNum : Integer; + Data : array [0..0] of Byte; + end; + + {.Z+} + { base component for SysTools non-visual components} + TStComponent = class(TComponent) + protected {private} + function GetVersion : string; + procedure SetVersion(const Value : string); + + published + property Version : string + read GetVersion + write SetVersion + stored False; + end; + + { base component for TStExpressionEdit component } + TStBaseEdit = class(TEdit) + protected {private} + function GetVersion : string; + procedure SetVersion(const Value : string); + + published + property Version : string + read GetVersion + write SetVersion + stored False; + end; + {.Z-} + +{---Generic node routines---} +function DestroyNode(Container : TStContainer; Node : TStNode; + OtherData : Pointer) : Boolean; + {-Generic function to pass to iterator to destroy a container node} + + +{---WIN32 short string routines---} +{$IFDEF WStrings} +function AnsiUpperCaseShort32(const S : string) : string; + {-Ansi uppercase for H- strings in WIN32} + +function AnsiCompareTextShort32(const S1, S2: string): Integer; + {-Case-insensitive compare function for H- strings in WIN32} + +function AnsiCompareStrShort32(const S1, S2: string): Integer; + {-Case-sensitive compare function for H- strings in WIN32} +{$ENDIF} + + +{.Z+} +{---Huge memory routines---} +function HugeCompressRLE(const InBuffer; InLen : Longint; + var OutBuffer) : Longint; + {-Run length encode a buffer} + +function HugeDecompressRLE(const InBuffer; InLen : Longint; + var OutBuffer; OutLen : LongInt) : Longint; + {-Run length decode a buffer} + +procedure HugeFillChar(var Dest; Count : Longint; Value : Byte); + {-Fill huge memory block with byte value} + +procedure HugeFillStruc(var Dest; Count : Longint; + const Value; ValSize : Cardinal); + {-Fill huge memory block with structure value} + +procedure HugeMove(const Src; var Dest; Count : LongInt); + {-Copy huge memory block to another} + +procedure HugeGetMem(var P : Pointer; Size : LongInt); + {-Get huge memory block allocation} + +procedure HugeFreeMem(var P : Pointer; Size : LongInt); + {-Free huge memory block allocation} +{.Z-} + + +{---General purpose character manipulation---} + +function Upcase(C : AnsiChar) : AnsiChar; overload; +function Upcase(C : WideChar) : WideChar; overload; + {-Return the uppercase of a character. Provides international character + support.} + +function LoCase(C : AnsiChar) : AnsiChar; overload; +function LoCase(C : WideChar) : WideChar; overload; + {-Return the lowercase of a character. Provides international character + support.} + +{---General comparison and searching---} + +function CompareLetterSets(Set1, Set2 : LongInt) : Cardinal; + {-Return the sum of the values of the letters common to Set1 and Set2.} + +function CompStruct(const S1, S2; Size : Cardinal) : Integer; + {-Compare two fixed size structures.} + +function Search(const Buffer; BufLength : Cardinal; const Match; + MatLength : Cardinal; var Pos : Cardinal) : Boolean; + {-Search a buffer for the specified pattern of bytes.} + +function SearchUC(const Buffer; BufLength : Cardinal; const Match; + MatLength : Cardinal; var Pos : Cardinal) : Boolean; + {-Search a buffer for a specified pattern of bytes. This search is not case + sensitive.} + + +{---Miscellaneous---} + +{.Z+} +function IsOrInheritsFrom(Root, Candidate : TClass) : boolean; + {-Return true if the classes are equal or Candidate is a descendant of Root} + +procedure RaiseContainerError(Code : longint); + {-Internal routine: raise an exception for a container} + +procedure RaiseContainerErrorFmt(Code : Longint; Data : array of const); + {-Internal routine: raise an exception for a container} + +function ProductOverflow(A, B : LongInt) : Boolean; + {-Return True if A*B exceeds MaxLongInt} + +{$IFNDEF HStrings} +function StNewStr(S : string) : PShortString; + {-Allocate a short string on the heap} + +procedure StDisposeStr(PS : PShortString); + {-Deallocate a short string from the heap} +{$ENDIF} +{.Z-} + + +{---primitives for converting strings to integers} +procedure ValLongInt(S : ShortString; var LI : Longint; var ErrorCode : integer); +procedure ValSmallint(const S : ShortString; var SI : smallint; var ErrorCode : integer); +procedure ValWord(const S : ShortString; var Wd : word; var ErrorCode : integer); + +{.Z+} +{general routine to raise a specific class of SysTools exception} +procedure RaiseStError(ExceptionClass : EStExceptionClass; Code : LongInt); +{.Z-} + +{.Z+} +{general routines to raise a specific Win32 exception in SysTools} +procedure RaiseStWin32Error(ExceptionClass : EStExceptionClass; Code : LongInt); +procedure RaiseStWin32ErrorEx(ExceptionClass : EStExceptionClass; Code : LongInt; Info : string); +{.Z-} + +{$IFDEF VERSION3ONLY} +var + StHexDigitsW : WideString; + DosDelimSetW : WideString; +{$ENDIF} + + +implementation + +procedure RaiseStError(ExceptionClass : EStExceptionClass; Code : LongInt); +var + E : EStException; +begin + E := ExceptionClass.CreateResTP(Code, 0); + E.ErrorCode := Code; + raise E; +end; + +procedure RaiseStWin32Error(ExceptionClass : EStExceptionClass; Code : LongInt); +var + E : EStException; +begin + E := ExceptionClass.Create(SysErrorMessage(Code)); + E.ErrorCode := Code; + raise E; +end; + +procedure RaiseStWin32ErrorEx(ExceptionClass : EStExceptionClass; Code : LongInt; + Info : string); +var + E : EStException; +begin + E := ExceptionClass.Create(SysErrorMessage(Code) + ' [' + Info + ']'); + E.ErrorCode := Code; + raise E; +end; + +constructor EStException.CreateResTP(Ident : LongInt; Dummy : Word); +begin + inherited Create(SysToolsStr(Ident)); +end; + +constructor EStException.CreateResFmtTP(Ident : Longint; + const Args : array of const; Dummy : Word); +begin + inherited CreateFmt(SysToolsStr(Ident), Args); +end; + +constructor EStExprError.CreateResTPCol(Ident : Longint; Column : Integer; Dummy : Integer); +begin + inherited CreateResTP(Ident, 0); + + FErrorCol := Column; +end; + + +function AbstractCompare(Data1, Data2 : Pointer) : Integer; far; +begin + raise ESTContainerError.CreateResTP(stscNoCompare, 0); +end; + +{$IFDEF WStrings} +function AnsiCompareStrShort32(const S1, S2: AnsiString): Integer; assembler; +asm + push esi + push edi + mov esi,S1 + mov edi,S2 + xor eax,eax + xor edx,edx + xor ecx,ecx + mov dl,[esi] + inc esi + mov dh,[edi] + inc edi + mov cl,dl + cmp cl,dh + jbe @1 + mov cl,dh +@1: + or ecx, ecx + je @CheckLengths + repe cmpsb + jb @LT + ja @GT +@CheckLengths: + cmp dl, dh + je @Exit + jb @LT +@GT: + inc eax + inc eax +@LT: + dec eax +@Exit: + pop edi + pop esi +end; + +function AnsiCompareTextShort32(const S1, S2: string): Integer; +begin + Result := AnsiCompareStrShort32(AnsiUpperCaseShort32(S1), + AnsiUpperCaseShort32(S2)); +end; + +function AnsiUpperCaseShort32(const S : string) : string; +begin + Result := S; + AnsiUpperBuff(PChar(@Result[1]), Length(S)); +end; +{$ENDIF} + +function DestroyNode(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; +begin + Container.DisposeNodeData(Node); + Node.Free; + Result := True; +end; + +procedure HugeFillChar(var Dest; Count : Longint; Value : Byte); +begin + FillChar(Dest, Count, Value); +end; + +function HugeCompressRLE(const InBuffer; InLen : Longint; + var OutBuffer) : Longint; + {assumes OutBuffer is at least InLen long} + {returns -1 if InLen <= 1 or if output length would exceed InLen} + {otherwise returns compressed length} + {does not initialize OutBuffer if the result is -1} + asm + {InBuffer = eax, InLen = edx, OutBuffer = ecx} + push ebx + push esi + push edi + + push OutBuffer {save output base for later} + + cmp InLen,1 + jle @A {can't compress if input length <= 1} + + mov esi,InBuffer {esi = current input offset} + mov edi,OutBuffer {edi = current output offset} + mov eax,InLen + mov ebx,edi {ebx = control byte offset} + mov byte ptr [ebx],0 {reset first control byte} + mov edx,edi + add edx,eax {edx = endpoint of output buffer} + dec edx {reserve an extra space for control byte} + mov ecx,esi + add ecx,eax {ecx = endpoint of input buffer} + dec ecx {reduce by one for convenience below} + dec esi {decrement first time through} + +@1: inc esi {next input byte} + cmp esi,ecx + ja @9 {exit at end of input} + mov al,[esi] {load compare byte} + jae @5 {can't be a match if on last byte of input} + cmp [esi+1],al {is it a run?} + jne @5 {jump if not} + + {starting a run} + mov ebx,edi {start a new control sequence} + mov byte ptr [ebx],1 {first byte in run} + mov [ebx+1],al {store run byte} +@2: inc esi {next input byte} + cmp esi,ecx {end of input?} + ja @3 {exit this loop if so} + cmp [esi],al {next byte a match?} + jne @3 {jump if not a run} + cmp byte ptr [ebx],StRLEMaxCount {max run length?} + je @3 {exit this loop if so} + inc byte ptr [ebx] {increment control byte} + jmp @2 {stay in the run loop} +@3: or byte ptr [ebx],StRLERunMode {flag control byte as a run} + inc edi {step past control and run bytes} + inc edi + cmp edi,edx {filled up output buffer?} + jae @A {jump if so} + mov ebx,edi {set up new control byte} + mov byte ptr [ebx],0 {first byte in non-run} + dec esi {back up one byte} + jmp @1 {classify run status again} + +@5: {not a run} + cmp edi,ebx {the start of a new non-run?} + ja @6 {jump if not} + inc edi {next output position, guaranteed ok} +@6: cmp byte ptr [ebx],StRLEMaxCount {max non-run length?} + jb @7 + mov ebx,edi {start a new control sequence} + mov byte ptr [ebx],0 {reset control byte} + inc edi {next output position} + cmp edi,edx {filled up output buffer?} + jae @A {jump if so} +@7: inc byte ptr [ebx] {increment control byte} + mov [edi],al {copy input byte} + inc edi {next output position} + cmp edi,edx {filled up output buffer?} + jae @A {jump if so} + jmp @1 {back to outer loop} + +@9: pop eax {get output base again} + sub edi,eax {get output length} + jmp @B +@A: pop eax {balance stack} + mov edi,-1 {could not compress input} +@B: mov eax,edi {return output length} + + pop edi + pop esi + pop ebx + end; + +function HugeDecompressRLE(const InBuffer; InLen : Longint; + var OutBuffer; OutLen : LongInt) : Longint; + {returns -1 if InLen is <= 0 or output length > OutLen} + {otherwise returns decompressed length} + asm + {InBuffer = eax, InLen = edx, OutBuffer = ecx, OutLen = stack} + push ebx + push esi + push edi + + push OutBuffer {save output base for later} + + cmp InLen,0 {anything to decompress?} + jle @A {jump if not} + + mov esi,InBuffer {esi = current input offset} + mov edi,OutBuffer {edi = current output offset} + mov ebx,esi + add ebx,InLen {ebx = endpoint of input buffer} + mov edx,OutLen {edx = space free in output buffer} + +@1: cmp esi,ebx {end of input?} + jae @9 {jump if so} + mov al,[esi] {get next control byte} + inc esi {move to run data byte} + mov cl,al + and ecx,StRLEMaxCount{ecx = bytes for output} + sub edx,ecx {is there space?} + jc @A {jump if not} + test al,StRLERunMode {is it a run?} + jz @5 {jump if not} + + {a run} + mov al,[esi] {get run data} + inc esi {next input position} + rep stosb {store it} + jmp @1 {loop} + +@5: {not a run} + rep movsb {copy them} + jmp @1 {loop} + +@9: pop eax {get output base again} + sub edi,eax {get output length} + jmp @B +@A: pop eax {balance stack} + mov edi,-1 {could not decompress input} +@B: mov eax,edi {return output length} + + pop edi + pop esi + pop ebx + end; + +procedure HugeFillStruc(var Dest; Count : Longint; + const Value; ValSize : Cardinal); assembler; +register; + asm + {eax = Dest, edx = Count, ecx = Value} + push ebx + push esi + push edi + mov edi,Dest {edi -> Dest} + mov eax,Value {eax -> Value} + {mov edx,Count} {edx = Count, register parameter} + mov ebp,ValSize {ebp = ValSize} + jmp @2 +@1: mov ecx,ebp {ecx = element ValSize} + mov esi,eax {esi -> Value} + mov bx,cx + shr ecx,2 + rep movsd + mov cx,bx + and cx,3 + rep movsb +@2: sub edx,1 {decrement elements left to fill} + jnc @1 {loop for all elements} + pop edi + pop esi + pop ebx + end; + +procedure HugeFreeMem(var P : Pointer; Size : LongInt); +begin + if Assigned(P) then begin + FreeMem(P, Size); + P := nil; + end; +end; + +procedure HugeGetMem(var P : Pointer; Size : LongInt); +begin + GetMem(P, Size); +end; + +procedure HugeMove(const Src; var Dest; Count : LongInt); +begin + Move(Src, Dest, Count); +end; + +function UpCase(C: AnsiChar) : AnsiChar; +{$IFDEF FPC} +begin + Result := System.Upcase(c); +end; +{$ELSE} +asm + and eax, 0FFh + push eax + call CharUpperA +end; +{$ENDIF} + +function UpCase(C: WideChar) : WideChar; +{$IFDEF FPC} +begin + Result := System.Upcase(C); +end; +{$ELSE} +asm + and eax, 0FFFFh + push eax + call CharUpperW +end; +{$ENDIF} + +{$IFDEF FPC} +function LoCase(C: AnsiChar) : AnsiChar; +begin + Result := LowerCase(c); +end; +{$ELSE} +function LoCase(C: AnsiChar) : AnsiChar; assembler; +asm + and eax, 0FFh + push eax + call CharLowerA +end; +{$ENDIF} + +function LoCase(C: WideChar) : WideChar; +{$IFDEF FPC} +begin + Result := LowerCase(c); +end; +{$ELSE} +function LoCase(C: WideChar) : WideChar; assembler; +asm + and eax, 0FFFFh + push eax + call CharLowerW +end; +{$ENDIF} + +function ProductOverflow(A, B : LongInt) : Boolean; +register; +asm + mov ecx,False + {A is in eax already, B is in edx already} + imul eax,edx + jno @1 + mov ecx,True +@1: + mov eax,ecx +end; + +function CompareLetterSets(Set1, Set2 : LongInt) : Cardinal; + {-Returns the sum of the values of the letters common to Set1 and Set2.} +asm + push ebx { Save registers } + push edi + and eax, edx { EAX = EAX and EDX } + xor edx, edx { Zero EDX } + mov ecx, ('Z'-'A') { Set up counter } + mov edi, offset StLetterValues{ Point EBX to table } + xor ebx, ebx + jmp @@Start + +@@Next: + dec ecx { Decrement counter } + shl eax, 1 { Shift next bit into position } + +@@Start: + test eax, 2000000h { Test 26th bit } + jnz @@Add { If set, add corresponding letter value } + or ecx, ecx + jz @@Exit { Done if ECX is zero } + jmp @@Next { Test next bit } + +@@Add: + mov bl, [ecx+edi] { Do table lookup } + add edx, ebx { Add value to result } + or ecx, ecx + jnz @@Next { Test next bit } + +@@Exit: + mov eax, edx { Move EDX to result } + pop edi { Restore registers } + pop ebx +end; + +function CompStruct(const S1, S2; Size : Cardinal) : Integer; + {-Compare two fixed size structures} +asm + push edi + push esi + mov esi, eax + mov edi, edx + xor eax, eax + or ecx, ecx + jz @@CSDone + + repe cmpsb + je @@CSDone + + inc eax + ja @@CSDone + or eax, -1 + +@@CSDone: + pop esi + pop edi +end; + + +function Search(const Buffer; BufLength : Cardinal; const Match; + MatLength : Cardinal; var Pos : Cardinal) : Boolean; +asm + push ebx + push edi + push esi + + cld + mov edi, eax + mov ebx, eax + mov esi, ecx + mov ecx, edx + mov edx, MatLength + or edx, edx + jz @@NotFound + + mov al, [esi] + inc esi + dec edx + sub ecx, edx + jbe @@NotFound + +@@Next: + repne scasb + jne @@NotFound + or edx, edx + jz @@Found + + push ecx + push edi + push esi + + mov ecx, edx + repe cmpsb + + pop esi + pop edi + pop ecx + + jne @@Next {Try again if no match} + +{Calculate number of bytes searched and return} +@@Found: + mov esi, Pos + dec edi + sub edi, ebx + mov eax, 1 + mov [esi], edi + jmp @@SDone + +{Match was not found} +@@NotFound: + xor eax, eax + +@@SDone: + pop esi + pop edi + pop ebx +end; + +function SearchUC(const Buffer; BufLength : Cardinal; const Match; + MatLength: Cardinal; var Pos : Cardinal) : Boolean; + +asm + push ebx { Save registers } + push edi + push esi + push eax + + mov edi, eax { EDI = ^Buffer } + mov esi, ecx { ESI = ^Match } + mov ecx, edx { ECX = BufLength } + mov edx, MatLength { EDX = MatLength } + xor ebx, ebx { EBX will be used for comparison } + or edx, edx { Is MatLength 0? } + jz @@NotFound + + mov al, [esi] { Get first character } + inc esi + and eax, 0FFh { Zero all but lower byte } + + push ecx { Save registers } + push edx + push eax + call CharUpper { Upcase character } + pop edx + pop ecx + + mov bl, al { Move uppercased char to BL } + dec edx { Dec MatLength } + sub ecx, edx { Is MatLength > BufLength? } + jbe @@NotFound + +@@Next: + mov al, [edi] + inc edi + + push ecx { Save registers } + push edx + push eax + call CharUpper { Upcase character in buffer } + pop edx + pop ecx + + cmp bl, al { Match? } + je @@CompRest { Compare rest of string } +@@RestNoMatch: + dec ecx { End of string? } + jnz @@Next { Try next char } + jmp @@NotFound { Done if not found } + +@@CompRest: + or edx, edx { Was there only one character? } + jz @@Found { If so, we're done } + + push ebx { Save registers } + push ecx + push edi + push esi + + mov ecx, edx + +@@CompLoop: + mov al, [esi] + inc esi + + push ecx { Save registers } + push edx + push eax + call CharUpper { Upcase character in buffer } + + mov bl, al + mov al, [edi] + inc edi + + push eax + call CharUpper { Upcase character in buffer } + pop edx + pop ecx + + cmp bl, al + jne @@NoComp + dec ecx + jnz @@CompLoop + +@@NoComp: + pop esi { Restore registers } + pop edi + pop ecx + pop ebx + + jne @@RestNoMatch { Try again if no match } + +{Calculate number of bytes searched and return} +@@Found: + pop ebx + mov esi, Pos + dec edi + sub edi, ebx + mov eax, 1 + mov [esi], edi + jmp @@SDone + +{Match was not found} +@@NotFound: + pop eax + xor eax, eax + +@@SDone: + pop esi + pop edi + pop ebx +end; + +{---primitives for converting strings to integers---} +procedure ValLongInt(S : ShortString; var LI : Longint; var ErrorCode : integer); +var + LenS : byte absolute S; + Offset : Integer; + NBCInx : Integer; +begin + {trim trailing spaces} + while (LenS > 0) and (S[LenS] = ' ') do + dec(LenS); + {empty strings are invalid} + if (LenS = 0) then begin + LI := 0; + ErrorCode := -1; + end; + {from now on S must have at least one non-blank char} + + {find the first non-blank char} + NBCInx := 1; + while (S[NBCInx] = ' ') do + inc(NBCInx); + + {check for a string of the form nnnnH} + Offset := 0; + if (stbase.upcase(S[LenS]) = 'H') then begin + {if the first non-blank char is the final character, then the + string is just of the form <spaces>H and is invalid} + if (NBCInx = LenS) then begin + LI := 0; + ErrorCode := LenS; + Exit; + end; + Move(S[NBCInx], S[NBCInx+1], LenS-NBCInx); + S[NBCInx] := '$'; + Offset := -1; + end + {check for a string of the form 0Xnnnn} + else begin + if (NBCInx < LenS) and + (S[NBCInx] = '0') and (stbase.upcase(S[NBCInx+1]) = 'X') then begin + S[NBCInx] := ' '; + S[NBCInx+1] := '$'; + end; + end; + Val(S, LI, ErrorCode); + if (ErrorCode <> 0) then begin + LI := 0; + Inc(ErrorCode, Offset); + end; +end; + +procedure ValSmallint(const S : ShortString; var SI : smallint; var ErrorCode : integer); +const + SmallestInt16 = -32767; + LargestInt16 = 32767; +var + LI : Longint; +begin + ValLongInt(S, LI, ErrorCode); + if (ErrorCode <> 0) then + SI := 0 + else {the conversion succeeded} begin + if (SmallestInt16 <= LI) and (LI <= LargestInt16) then + SI := LI + else begin + ErrorCode := length(S); + SI := 0; + end; + end; +end; + +procedure ValWord(const S : ShortString; var Wd : word; var ErrorCode : integer); +const + SmallestWord = 0; + LargestWord = 65535; +var + LI : Longint; +begin + ValLongInt(S, LI, ErrorCode); + if (ErrorCode <> 0) then + Wd := 0 + else {the conversion succeeded} begin + if (SmallestWord <= LI) and (LI <= LargestWord) then + Wd := LI + else begin + ErrorCode := length(S); + Wd := 0; + end; + end; +end; +{---------------------------------------------------} + + +function IsOrInheritsFrom(Root, Candidate : TClass) : boolean; + begin + Result := (Root = Candidate) or Candidate.InheritsFrom(Root); + end; + +procedure RaiseContainerError(Code : LongInt); +var + E : ESTContainerError; +begin + E := ESTContainerError.CreateResTP(Code, 0); + E.ErrorCode := Code; + raise E; +end; + +procedure RaiseContainerErrorFmt(Code : Longint; Data : array of const); +var + E : ESTContainerError; +begin + E := ESTContainerError.CreateResFmtTP(Code, Data, 0); + E.ErrorCode := Code; + raise E; +end; + +{$IFNDEF HStrings} +function StNewStr(S : AnsiString) : PShortString; +begin + GetMem(Result, succ(length(S))); + Result^ := S; +end; + +procedure StDisposeStr(PS : PShortString); +begin + if (PS <> nil) then + FreeMem(PS, succ(length(PS^))); +end; +{$ENDIF} + +{----------------------------------------------------------------------} + +constructor TStNode.Create(AData : Pointer); +begin + Data := AData; +end; + +{----------------------------------------------------------------------} + +function TStContainer.AssignPointers(Source : TPersistent; + AssignData : TIteratePointerFunc) : boolean; +begin + Result := false; + if (Source is TStContainer) then + if TStContainer(Source).StoresPointers then + begin + Clear; + TStContainer(Source).ForEachPointer(AssignData, Self); + Result := true; + end; +end; + +function TStContainer.AssignUntypedVars(Source : TPersistent; + AssignData : TIterateUntypedFunc) : boolean; +var + RowCount : Cardinal; + ColCount : Cardinal; + ElSize : Cardinal; +begin + Result := false; + if (Source is TStContainer) then + if TStContainer(Source).StoresUntypedVars then + begin + Clear; + TStContainer(Source).GetArraySizes(RowCount, ColCount, ElSize); + SetArraySizes(RowCount, ColCount, ElSize); + TStContainer(Source).ForEachUntypedVar(AssignData, Self); + Result := true; + end; +end; + +procedure TStContainer.ForEachPointer(Action : TIteratePointerFunc; + OtherData : pointer); +begin + {do nothing} +end; + +procedure TStContainer.ForEachUntypedVar(Action : TIterateUntypedFunc; + OtherData : pointer); +begin + {do nothing} +end; + +procedure TStContainer.GetArraySizes(var RowCount, ColCount, ElSize : Cardinal); +begin + RowCount := 0; + ColCount := 0; + ElSize := 0; +end; + +procedure TStContainer.SetArraySizes(RowCount, ColCount, ElSize : Cardinal); +begin + {do nothing} +end; + +procedure TStContainer.SetCompare(C : TCompareFunc); +begin + FCompare := C; +end; + +procedure TStContainer.SetDisposeData(D : TDisposeDataProc); +begin + FDisposeData := D; +end; + +procedure TStContainer.SetLoadData(L : TLoadDataFunc); +begin + FLoadData := L; +end; + +procedure TStContainer.SetStoreData(S : TStoreDataProc); +begin + FStoreData := S; +end; + +function TStContainer.StoresPointers : boolean; +begin + Result := false; +end; + +function TStContainer.StoresUntypedVars : boolean; +begin + Result := false; +end; + +constructor TStContainer.CreateContainer(NodeClass : TStNodeClass; Dummy : Integer); +begin +{$IFDEF ThreadSafe} + Windows.InitializeCriticalSection(conThreadSafe); +{$ENDIF} + + FCompare := AbstractCompare; + conNodeClass := NodeClass; + + inherited Create; +end; + +procedure TStContainer.DecNodeProtection; +begin + Dec(conNodeProt); +end; + +destructor TStContainer.Destroy; +begin + if conNodeProt = 0 then + Clear; +{$IFDEF ThreadSafe} + Windows.DeleteCriticalSection(conThreadSafe); +{$ENDIF} + inherited Destroy; +end; + +procedure TStContainer.DisposeNodeData(P : TStNode); +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if Assigned(P) then + DoDisposeData(P.Data); +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +function TStContainer.DoCompare(Data1, Data2 : Pointer) : Integer; +begin + Result := 0; + if Assigned(FOnCompare) then + FOnCompare(Self, Data1, Data2, Result) + else if Assigned(FCompare) then + Result := FCompare(Data1, Data2); +end; + +procedure TStContainer.DoDisposeData(Data : Pointer); +begin + if Assigned(FOnDisposeData) then + FOnDisposeData(Self, Data) + else if Assigned(FDisposeData) then + FDisposeData(Data); +end; + +function TStContainer.DoLoadData(Reader : TReader) : Pointer; +begin + Result := nil; + if Assigned(FOnLoadData) then + FOnLoadData(Self, Reader, Result) + else if Assigned(FLoadData) then + Result := FLoadData(Reader) + else + RaiseContainerError(stscNoLoadData); +end; + +procedure TStContainer.DoStoreData(Writer : TWriter; Data : Pointer); +begin + if Assigned(FOnStoreData) then + FOnStoreData(Self, Writer, Data) + else if Assigned(FStoreData) then + FStoreData(Writer, Data) + else + RaiseContainerError(stscNoStoreData); +end; + +procedure TStContainer.EnterCS; +begin +{$IFDEF ThreadSafe} + EnterCriticalSection(conThreadSafe); +{$ENDIF} +end; + +procedure TStContainer.IncNodeProtection; +begin + Inc(conNodeProt); +end; + +procedure TStContainer.LeaveCS; +begin +{$IFDEF ThreadSafe} + LeaveCriticalSection(conThreadSafe); +{$ENDIF} +end; + +procedure TStContainer.LoadFromFile(const FileName : string); +var + S : TStream; +begin + S := TFileStream.Create(FileName, fmOpenRead + fmShareDenyWrite); + try + LoadFromStream(S); + finally + S.Free; + end; +end; + +procedure TStContainer.StoreToFile(const FileName : string); +var + S : TStream; +begin + S := TFileStream.Create(FileName, fmCreate); + try + StoreToStream(S); + finally + S.Free; + end; +end; + + +{*** TStComponent ***} + +function TStComponent.GetVersion : string; +begin + Result := StVersionStr; +end; + +procedure TStComponent.SetVersion(const Value : string); +begin +end; + +{ TStBaseEdit } + +function TStBaseEdit.GetVersion : string; +begin + Result := StVersionStr; +end; + +procedure TStBaseEdit.SetVersion(const Value : string); +begin +end; + + + +initialization +{$IFDEF VERSION3ONLY} { Delphi/Builder 3 doesn't like widestring typed constants } + StHexDigitsW := '0123456789ABCDEF'; + DosDelimSetW := '\:'; +{$ENDIF} +end. + + diff --git a/components/systools/source/run/st2dbarc.pas b/components/systools/source/run/st2dbarc.pas new file mode 100644 index 000000000..eb5350681 --- /dev/null +++ b/components/systools/source/run/st2dbarc.pas @@ -0,0 +1,5254 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: St2DBarC.pas 4.04 *} +{*********************************************************} +{* SysTools: Two-Dimensional Barcodes *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit St2DBarC; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, + {$ENDIF} + SysUtils, + Classes, + Controls, + Graphics, + StdCtrls, + Math, + ClipBrd, + StConst; + +resourcestring + + StEBadBarHeight = 'Bar Height cannot be less than one'; + StEBadBarHeightToWidth = 'BarHeightToWidth cannot be less than one'; + StEBadBarWidth = 'Bar Width cannot be less than one'; + StEBadCountryCode = 'Invalid Country Code'; + StEBadNumCols = 'Invalid Number of columns'; + StEBadNumRows = 'Invalid number of rows'; + StEBadPostalCode = 'Invalid Postal Code'; + StEBadServiceClass = 'Invalid Service Class'; + StEBadQuietZone = 'Invalid Quiet Zone'; + StECodeTooLarge = 'Code too large for barcode'; + StEGLIOutOfRange = 'GLI value out of range'; + StEInvalidCodeword = 'Invalid Codeword'; + StENeedBarHeight = 'Either BarHeight or BarHeightToWidth is required'; + StENeedHorz = 'Horizontal size needs to be specified'; + StENeedVert = 'Vertical size needs to be specified'; + +type + { Generic 2D barcode types and constants } + + TStDataMode = (dmBinary, dmText, dmNumeric); + + { PDF417 types and constants } + + TStPDF417CodewordList = array [0..2700] of Word; + TStPDF417ECCLevels = (ecAuto, ecLevel0, ecLevel1, ecLevel2, ecLevel3, + ecLevel4, ecLevel5, ecLevel6, ecLevel7, ecLevel8); + + { MaxiCode types and constants } + + TStMaxiCodeMode = (cmMode2, cmMode3, cmMode4, cmMode5, cmMode6); + +const + StMaxiCodeGaloisField = 64; { Galois field to work in } + StMaxiCodeECCPoly = 67; { Primary polynomial - } + StMaxMaxiCodeECCDataSize = 144; { Max amount of data } + +type + TStMaxiCodeECCData = array [0..StMaxMaxiCodeECCDataSize] of Byte; + TStMaxiCodeECCPoly = (epPrimary, epStandard, epEnhanced); + TStMaxiCodeECCInterleave = (imNone, imEven, imOdd); + + { E2DBarcodeError } + + E2DBarcodeError = class (Exception); + + { TStCustom2DBarcode } + + TStCustom2DBarcode = class (TGraphicControl) + protected { private } + FCode : string; + FBarWidth : Integer; + FBackgroundColor : TColor; + FCaption : string; + FECCLevel : Integer; + FExtendedSyntax : Boolean; + FRelativeBarHeight : Boolean; + FBarHeightToWidth : Integer; + FBarHeight : Integer; + + FQuietZone : Integer; + FAlignment : TAlignment; + FCaptionLayout : TTextLayout; + FBarCodeRect : TRect; + FUsedCodewords : Integer; + FFreeCodewords : Integer; + FUsedECCCodewords : Integer; + FTotalCodewords : Integer; + + { protected } + FBitmap : TBitmap; + + function CalculateBarCodeWidth (PaintableWidth : Integer) : Integer; + virtual; abstract; + function CalculateBarCodeHeight (PaintableHeight : Integer) : Integer; + virtual; abstract; + procedure DrawBarcode; virtual; abstract; + procedure GenerateBarcodeBitmap (BCWidth : Integer; + BCHeight : Integer); + procedure GenerateCodewords; virtual; abstract; + function GetBarCodeHeight : Integer; + function GetBarCodeWidth : Integer; + procedure GetCurrentResolution (var ResX : Integer; var ResY : Integer); + function GetVersion : string; + procedure Paint; override; + procedure SetAlignment (const v : TAlignment); + procedure SetBackgroundColor (const v : TColor); + procedure SetBarHeight (const v : Integer); virtual; + procedure SetBarHeightToWidth (const v : Integer); virtual; + procedure SetBarWidth (const v : Integer); virtual; + procedure SetBitmap (const v : TBitmap); + procedure SetCaption (const v : string); + procedure SetCaptionLayout (const v : TTextLayout); + procedure SetCode (const v : string); + procedure SetECCLevel (const v : Integer); + procedure SetExtendedSyntax (const v : Boolean); + procedure SetRelativeBarHeight (const v : Boolean); virtual; + procedure SetQuietZone (const v : Integer); + procedure SetVersion(const Value : string); + + public + constructor Create (AOwner : TComponent); override; + destructor Destroy; override; + + procedure CopyToClipboard; + procedure CopyToClipboardRes (ResX : Integer; ResY : Integer); + procedure PaintToCanvas (ACanvas : TCanvas; Position : TPoint); + procedure PaintToCanvasRes (ACanvas : TCanvas; Position : TPoint; + ResX : Integer; ResY : Integer); + procedure PaintToCanvasSize (ACanvas : TCanvas; X, Y, H : Double); + procedure PaintToDC (DC : hDC; Position : TPoint); + procedure PaintToDCRes (DC : hDC; Position : TPoint; + ResX : Integer; ResY : Integer); + procedure PaintToPrinterCanvas (ACanvas : TCanvas; Position : TPoint); + procedure PaintToPrinterCanvasRes (ACanvas : TCanvas; Position : TPoint; + ResX : Integer; ResY : Integer); + procedure PaintToPrinterCanvasSize (ACanvas : TCanvas; X, Y, H : Double); + procedure PaintToPrinterDC (DC : hDC; Position : TPoint); + procedure PaintToPrinterDCRes (DC : hDC; Position : TPoint; + ResX : Integer; ResY : Integer); + procedure RenderToResolution (var OutBitmap : TBitmap; + ResX : Integer; + ResY : Integer; + var SizeX : Integer; + var SizeY : Integer); virtual; abstract; + procedure SaveToFile (const FileName : string); + procedure SaveToFileRes (const FileName : string; + ResX : Integer; ResY : Integer); + + property Alignment : TAlignment read FAlignment write SetAlignment + default taCenter; + property BackgroundColor : TColor + read FBackgroundColor write SetBackgroundColor default clWhite; + property BarCodeHeight : Integer read GetBarCodeHeight; + property BarCodeRect : TRect read FBarCodeRect; + property BarCodeWidth : Integer read GetBarCodeWidth; + property BarHeight : Integer read FBarHeight write SetBarHeight + default 2; + property BarHeightToWidth : Integer + read FBarHeightToWidth write SetBarHeightToWidth default 4; + property BarWidth : Integer read FBarWidth write SetBarWidth default 2; + property Bitmap : TBitmap read FBitmap write SetBitmap stored False; + property Caption : string read FCaption write SetCaption; + property CaptionLayout : TTextLayout + read FCaptionLayout write SetCaptionLayout + default tlBottom; + property Code : string read FCode write SetCode; + property ECCLevel : Integer read FECCLevel write SetECCLevel default 0; + property ExtendedSyntax : Boolean + read FExtendedSyntax write SetExtendedSyntax default True; + property FreeCodewords : Integer read FFreeCodewords; + property RelativeBarHeight : Boolean + read FRelativeBarHeight write SetRelativeBarHeight + default False; + property QuietZone : Integer read FQuietZone write SetQuietZone + default 8; + property TotalCodewords : Integer read FTotalCodewords; + property UsedCodewords : Integer read FUsedCodewords; + property UsedECCCodewords : Integer read FUsedECCCodewords; + + property Color default clBlack; + + published + property Version : string read GetVersion write SetVersion stored False; + + { Properties } + property Align; + property Cursor; + property Enabled; + property Font; + property ParentColor; + property ParentFont; + property ParentShowHint; + property ShowHint; + property Visible; + + { Events } + property OnClick; + property OnDblClick; + property OnMouseDown; + property OnMouseMove; + property OnMouseUp; + end; + + { TStPDF417Barcode } + + TStPDF417Barcode = class (TStCustom2DBarcode) + private + FTruncated : Boolean; + FCodewords : TStPDF417CodewordList; + FNumCodewords : Integer; + FNewTextCodeword : Boolean; + FHighlight : Boolean; + FNumRows : Integer; + FNumColumns : Integer; + + protected + procedure AddCodeword (Value : Word); + function CalculateBarCodeWidth (PaintableWidth : Integer) : Integer; + override; + function CalculateBarCodeHeight (PaintableHeight : Integer) : Integer; + override; + procedure CalculateECC (NumCodewords : Integer; ECCLen : Integer); + procedure CalculateSize (var XSize : Integer; + var YSize : Integer); + function CodewordToBitmask (RowNumber : Integer; + Codeword : Integer) : DWord; + procedure ConvertBytesToBase900 (const S : array of byte; + var A : array of integer); + procedure ConvertToBase900 (const S : string; + var A : array of integer; + var LenA : integer); + procedure DrawBarcode; override; + procedure DrawCodeword (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer; + Pattern : string); + procedure DrawCodewordBitmask (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer; + Bitmask : DWord); + procedure DrawLeftRowIndicator (RowNumber : Integer; + WorkBarHeight : Integer; + NumRows : Integer; + NumCols : Integer); + procedure DrawRightRowIndicator (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer; + NumRows : Integer; + NumCols : Integer); + procedure DrawStartPattern (RowNumber : Integer; + WorkBarHeight : Integer); + procedure DrawStopPattern (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer); + procedure EncodeBinary (var Position : Integer; CodeLen : Integer); + procedure EncodeNumeric (var Position : Integer; CodeLen : Integer); + procedure EncodeText (var Position : Integer; CodeLen : Integer); + procedure GenerateCodewords; override; + procedure GetNextCharacter (var NewChar : Integer; + var Codeword : Boolean; + var Position : Integer; + CodeLen : Integer); + function GetPDF417ECCLevel : TStPDF417ECCLevels; + function GetRealErrorLevel : Integer; + function GoodForNumericCompaction (Position : Integer; + CodeLen : Integer; + var Count : Integer) : Boolean; + function GoodForTextCompaction (Position : Integer; + CodeLen : Integer; + var Count : Integer) : Boolean; + function IsNumericString (const S : string) : boolean; + procedure SetBarHeight (const v : Integer); override; + procedure SetBarHeightToWidth (const v : Integer); override; + procedure SetBarWidth (const v : Integer); override; + procedure SetNumColumns (const v : Integer); + procedure SetNumRows (const v : Integer); + procedure SetPDF417ECCLevel (const v : TStPDF417ECCLevels); + procedure SetRelativeBarHeight (const v : Boolean); override; + procedure SetTruncated (const v : Boolean); + procedure TextToCodewords; + + public + constructor Create (AOwner : TComponent); override; + + procedure RenderToResolution (var OutBitmap : TBitmap; + ResX : Integer; + ResY : Integer; + var SizeX : Integer; + var SizeY : Integer); override; + + published + property ECCLevel : TStPDF417ECCLevels + read GetPDF417ECCLevel write SetPDF417ECCLevel default ecAuto; + property NumColumns : Integer read FNumColumns write SetNumColumns + default 0; + property NumRows : Integer read FNumRows write SetNumRows + default 0; + property Truncated : Boolean read FTruncated write SetTruncated + default False; + + property Alignment; + property BackgroundColor; + property BarCodeHeight; + property BarCodeWidth; + property BarHeight; + property BarHeightToWidth; + property BarWidth; + property Bitmap; + property CaptionLayout; + property Code; + property ExtendedSyntax; + property Height default 81; + property RelativeBarHeight; + property QuietZone; + property Width default 273; + + property Caption; + property Color; + property Font; + end; + + { TStMaxiCodeBarcode } + + TStMaxiCodeBarcode = class (TStCustom2DBarcode) + private + FMode : TStMaxiCodeMode; + FCodewords : TStMaxiCodeECCData; + FNumCodewords : Integer; + FHighlight : Boolean; + FShowCodewords : Boolean; + FShowAll : Boolean; + FMessage : TStMaxiCodeECCData; + FCarrierCountryCode : Integer; + FCarrierPostalCode : string; + FCarrierServiceClass : Integer; + FAutoScale : Boolean; + FHorPixelsPerMM : Extended; + FVerPixelsPerMM : Extended; + FMaxiHexWidth : Extended; + FMaxiHexHeight : Extended; + FMaxiHexVOffset : Extended; + FMaxiHexHOffset : Extended; + + { Log and AnitLog data for Galois field arithmetic } + FLog : array [0..StMaxiCodeGaloisField] of Integer; + FAntiLog : array [0..StMaxiCodeGaloisField] of Integer; + + protected + procedure AddCodeword (Value : Integer); + function CalculateBarCodeWidth (PaintableWidth : Integer) : Integer; + override; + function CalculateBarCodeHeight (PaintableHeight : Integer) : Integer; + override; + procedure DrawBarcode; override; + procedure DrawFinder; + procedure DrawHex (XPos, YPos : Integer); + procedure GenerateCodewords; override; + procedure GenerateECC; + procedure GetNextCharacter (var NewChar : Integer; + var Codeword : Boolean; + var Position : Integer; + CodeLen : Integer); + procedure GetSizes; + procedure GetSizesEx (ResX : Integer; ResY : Integer); + procedure PlotCell (Row : Integer; Col : Integer); + procedure SetAutoScale (const v : Boolean); + procedure SetBarHeight (const v : Integer); override; + procedure SetBarWidth (const v : Integer); override; + procedure SetCarrierCountryCode (const v : Integer); + procedure SetCarrierPostalCode (const v : string); + procedure SetCarrierServiceClass (const v : Integer); + procedure SetMode (const v : TStMaxiCodeMode); + procedure SetHorPixelsPerMM (const v : Extended); + procedure SetVerPixelsPerMM (const v : Extended); + procedure TextToCodewords; + + public + constructor Create (AOwner : TComponent); override; + + procedure RenderToResolution (var OutBitmap : TBitmap; + ResX : Integer; + ResY : Integer; + var SizeX : Integer; + var SizeY : Integer); override; + + published + property AutoScale : Boolean + read FAutoScale write SetAutoScale default True; + property CarrierCountryCode : Integer + read FCarrierCountryCode write SetCarrierCountryCode default 0; + property CarrierPostalCode : string + read FCarrierPostalCode write SetCarrierPostalCode; + property CarrierServiceClass : Integer + read FCarrierServiceClass write SetCarrierServiceClass + default 0; + property HorPixelsPerMM : Extended + read FHorPixelsPerMM write SetHorPixelsPerMM; + + property Mode : TStMaxiCodeMode + read FMode write SetMode default cmMode4; + property VerPixelsPerMM : Extended + read FVerPixelsPerMM write SetVerPixelsPerMM; + + property Alignment; + property BackgroundColor; + property BarCodeHeight; + property BarCodeWidth; + property BarHeight default 0; + property BarWidth default 0; + property Bitmap; + property CaptionLayout; + property Code; + property ExtendedSyntax; + property Height default 129; + property QuietZone; + property Width default 121; + + property Caption; + property Color; + property Font; + end; + + +implementation + { PDF417 types and constants } + +type + TStPDF417CodewordArray = array [0..2] of array [0..928] of Longint; + +const + + StPDF417CellWidth = 17; + + StPDF417Codewords : TstPDF417CodewordArray = + (($1d5c0, $1eaf0, $1f57c, $1d4e0, $1ea78, $1f53e, $1a8c0, $1d470, $1a860, + $15040, $1a830, $15020, $1adc0, $1d6f0, $1eb7c, $1ace0, $1d678, $1eb3e, + $158c0, $1ac70, $15860, $15dc0, $1aef0, $1d77c, $15ce0, $1ae78, $1d73e, + $15c70, $1ae3c, $15ef0, $1af7c, $15e78, $1af3e, $15f7c, $1f5fa, $1d2e0, + $1e978, $1f4be, $1a4c0, $1d270, $1e93c, $1a460, $1d238, $14840, $1a430, + $1d21c, $14820, $1a418, $14810, $1a6e0, $1d378, $1e9be, $14cc0, $1a670, + $1d33c, $14c60, $1a638, $1d31e, $14c30, $1a61c, $14ee0, $1a778, $1d3be, + $14e70, $1a73c, $14e38, $1a71e, $14f78, $1a7be, $14f3c, $14f1e, $1a2c0, + $1d170, $1e8bc, $1a260, $1d138, $1e89e, $14440, $1a230, $1d11c, $14420, + $1a218, $14410, $14408, $146c0, $1a370, $1d1bc, $14660, $1a338, $1d19e, + $14630, $1a31c, $14618, $1460c, $14770, $1a3bc, $14738, $1a39e, $1471c, + $147bc, $1a160, $1d0b8, $1e85e, $14240, $1a130, $1d09c, $14220, $1a118, + $1d08e, $14210, $1a10c, $14208, $1a106, $14360, $1a1b8, $1d0de, $14330, + $1a19c, $14318, $1a18e, $1430c, $14306, $1a1de, $1438e, $14140, $1a0b0, + $1d05c, $14120, $1a098, $1d04e, $14110, $1a08c, $14108, $1a086, $14104, + $141b0, $14198, $1418c, $140a0, $1d02e, $1a04c, $1a046, $14082, $1cae0, + $1e578, $1f2be, $194c0, $1ca70, $1e53c, $19460, $1ca38, $1e51e, $12840, + $19430, $12820, $196e0, $1cb78, $1e5be, $12cc0, $19670, $1cb3c, $12c60, + $19638, $12c30, $12c18, $12ee0, $19778, $1cbbe, $12e70, $1973c, $12e38, + $12e1c, $12f78, $197be, $12f3c, $12fbe, $1dac0, $1ed70, $1f6bc, $1da60, + $1ed38, $1f69e, $1b440, $1da30, $1ed1c, $1b420, $1da18, $1ed0e, $1b410, + $1da0c, $192c0, $1c970, $1e4bc, $1b6c0, $19260, $1c938, $1e49e, $1b660, + $1db38, $1ed9e, $16c40, $12420, $19218, $1c90e, $16c20, $1b618, $16c10, + $126c0, $19370, $1c9bc, $16ec0, $12660, $19338, $1c99e, $16e60, $1b738, + $1db9e, $16e30, $12618, $16e18, $12770, $193bc, $16f70, $12738, $1939e, + $16f38, $1b79e, $16f1c, $127bc, $16fbc, $1279e, $16f9e, $1d960, $1ecb8, + $1f65e, $1b240, $1d930, $1ec9c, $1b220, $1d918, $1ec8e, $1b210, $1d90c, + $1b208, $1b204, $19160, $1c8b8, $1e45e, $1b360, $19130, $1c89c, $16640, + $12220, $1d99c, $1c88e, $16620, $12210, $1910c, $16610, $1b30c, $19106, + $12204, $12360, $191b8, $1c8de, $16760, $12330, $1919c, $16730, $1b39c, + $1918e, $16718, $1230c, $12306, $123b8, $191de, $167b8, $1239c, $1679c, + $1238e, $1678e, $167de, $1b140, $1d8b0, $1ec5c, $1b120, $1d898, $1ec4e, + $1b110, $1d88c, $1b108, $1d886, $1b104, $1b102, $12140, $190b0, $1c85c, + $16340, $12120, $19098, $1c84e, $16320, $1b198, $1d8ce, $16310, $12108, + $19086, $16308, $1b186, $16304, $121b0, $190dc, $163b0, $12198, $190ce, + $16398, $1b1ce, $1638c, $12186, $16386, $163dc, $163ce, $1b0a0, $1d858, + $1ec2e, $1b090, $1d84c, $1b088, $1d846, $1b084, $1b082, $120a0, $19058, + $1c82e, $161a0, $12090, $1904c, $16190, $1b0cc, $19046, $16188, $12084, + $16184, $12082, $120d8, $161d8, $161cc, $161c6, $1d82c, $1d826, $1b042, + $1902c, $12048, $160c8, $160c4, $160c2, $18ac0, $1c570, $1e2bc, $18a60, + $1c538, $11440, $18a30, $1c51c, $11420, $18a18, $11410, $11408, $116c0, + $18b70, $1c5bc, $11660, $18b38, $1c59e, $11630, $18b1c, $11618, $1160c, + $11770, $18bbc, $11738, $18b9e, $1171c, $117bc, $1179e, $1cd60, $1e6b8, + $1f35e, $19a40, $1cd30, $1e69c, $19a20, $1cd18, $1e68e, $19a10, $1cd0c, + $19a08, $1cd06, $18960, $1c4b8, $1e25e, $19b60, $18930, $1c49c, $13640, + $11220, $1cd9c, $1c48e, $13620, $19b18, $1890c, $13610, $11208, $13608, + $11360, $189b8, $1c4de, $13760, $11330, $1cdde, $13730, $19b9c, $1898e, + $13718, $1130c, $1370c, $113b8, $189de, $137b8, $1139c, $1379c, $1138e, + $113de, $137de, $1dd40, $1eeb0, $1f75c, $1dd20, $1ee98, $1f74e, $1dd10, + $1ee8c, $1dd08, $1ee86, $1dd04, $19940, $1ccb0, $1e65c, $1bb40, $19920, + $1eedc, $1e64e, $1bb20, $1dd98, $1eece, $1bb10, $19908, $1cc86, $1bb08, + $1dd86, $19902, $11140, $188b0, $1c45c, $13340, $11120, $18898, $1c44e, + $17740, $13320, $19998, $1ccce, $17720, $1bb98, $1ddce, $18886, $17710, + $13308, $19986, $17708, $11102, $111b0, $188dc, $133b0, $11198, $188ce, + $177b0, $13398, $199ce, $17798, $1bbce, $11186, $13386, $111dc, $133dc, + $111ce, $177dc, $133ce, $1dca0, $1ee58, $1f72e, $1dc90, $1ee4c, $1dc88, + $1ee46, $1dc84, $1dc82, $198a0, $1cc58, $1e62e, $1b9a0, $19890, $1ee6e, + $1b990, $1dccc, $1cc46, $1b988, $19884, $1b984, $19882, $1b982, $110a0, + $18858, $1c42e, $131a0, $11090, $1884c, $173a0, $13190, $198cc, $18846, + $17390, $1b9cc, $11084, $17388, $13184, $11082, $13182, $110d8, $1886e, + $131d8, $110cc, $173d8, $131cc, $110c6, $173cc, $131c6, $110ee, $173ee, + $1dc50, $1ee2c, $1dc48, $1ee26, $1dc44, $1dc42, $19850, $1cc2c, $1b8d0, + $19848, $1cc26, $1b8c8, $1dc66, $1b8c4, $19842, $1b8c2, $11050, $1882c, + $130d0, $11048, $18826, $171d0, $130c8, $19866, $171c8, $1b8e6, $11042, + $171c4, $130c2, $171c2, $130ec, $171ec, $171e6, $1ee16, $1dc22, $1cc16, + $19824, $19822, $11028, $13068, $170e8, $11022, $13062, $18560, $10a40, + $18530, $10a20, $18518, $1c28e, $10a10, $1850c, $10a08, $18506, $10b60, + $185b8, $1c2de, $10b30, $1859c, $10b18, $1858e, $10b0c, $10b06, $10bb8, + $185de, $10b9c, $10b8e, $10bde, $18d40, $1c6b0, $1e35c, $18d20, $1c698, + $18d10, $1c68c, $18d08, $1c686, $18d04, $10940, $184b0, $1c25c, $11b40, + $10920, $1c6dc, $1c24e, $11b20, $18d98, $1c6ce, $11b10, $10908, $18486, + $11b08, $18d86, $10902, $109b0, $184dc, $11bb0, $10998, $184ce, $11b98, + $18dce, $11b8c, $10986, $109dc, $11bdc, $109ce, $11bce, $1cea0, $1e758, + $1f3ae, $1ce90, $1e74c, $1ce88, $1e746, $1ce84, $1ce82, $18ca0, $1c658, + $19da0, $18c90, $1c64c, $19d90, $1cecc, $1c646, $19d88, $18c84, $19d84, + $18c82, $19d82, $108a0, $18458, $119a0, $10890, $1c66e, $13ba0, $11990, + $18ccc, $18446, $13b90, $19dcc, $10884, $13b88, $11984, $10882, $11982, + $108d8, $1846e, $119d8, $108cc, $13bd8, $119cc, $108c6, $13bcc, $119c6, + $108ee, $119ee, $13bee, $1ef50, $1f7ac, $1ef48, $1f7a6, $1ef44, $1ef42, + $1ce50, $1e72c, $1ded0, $1ef6c, $1e726, $1dec8, $1ef66, $1dec4, $1ce42, + $1dec2, $18c50, $1c62c, $19cd0, $18c48, $1c626, $1bdd0, $19cc8, $1ce66, + $1bdc8, $1dee6, $18c42, $1bdc4, $19cc2, $1bdc2, $10850, $1842c, $118d0, + $10848, $18426, $139d0, $118c8, $18c66, $17bd0, $139c8, $19ce6, $10842, + $17bc8, $1bde6, $118c2, $17bc4, $1086c, $118ec, $10866, $139ec, $118e6, + $17bec, $139e6, $17be6, $1ef28, $1f796, $1ef24, $1ef22, $1ce28, $1e716, + $1de68, $1ef36, $1de64, $1ce22, $1de62, $18c28, $1c616, $19c68, $18c24, + $1bce8, $19c64, $18c22, $1bce4, $19c62, $1bce2, $10828, $18416, $11868, + $18c36, $138e8, $11864, $10822, $179e8, $138e4, $11862, $179e4, $138e2, + $179e2, $11876, $179f6, $1ef12, $1de34, $1de32, $19c34, $1bc74, $1bc72, + $11834, $13874, $178f4, $178f2, $10540, $10520, $18298, $10510, $10508, + $10504, $105b0, $10598, $1058c, $10586, $105dc, $105ce, $186a0, $18690, + $1c34c, $18688, $1c346, $18684, $18682, $104a0, $18258, $10da0, $186d8, + $1824c, $10d90, $186cc, $10d88, $186c6, $10d84, $10482, $10d82, $104d8, + $1826e, $10dd8, $186ee, $10dcc, $104c6, $10dc6, $104ee, $10dee, $1c750, + $1c748, $1c744, $1c742, $18650, $18ed0, $1c76c, $1c326, $18ec8, $1c766, + $18ec4, $18642, $18ec2, $10450, $10cd0, $10448, $18226, $11dd0, $10cc8, + $10444, $11dc8, $10cc4, $10442, $11dc4, $10cc2, $1046c, $10cec, $10466, + $11dec, $10ce6, $11de6, $1e7a8, $1e7a4, $1e7a2, $1c728, $1cf68, $1e7b6, + $1cf64, $1c722, $1cf62, $18628, $1c316, $18e68, $1c736, $19ee8, $18e64, + $18622, $19ee4, $18e62, $19ee2, $10428, $18216, $10c68, $18636, $11ce8, + $10c64, $10422, $13de8, $11ce4, $10c62, $13de4, $11ce2, $10436, $10c76, + $11cf6, $13df6, $1f7d4, $1f7d2, $1e794, $1efb4, $1e792, $1efb2, $1c714, + $1cf34, $1c712, $1df74, $1cf32, $1df72, $18614, $18e34, $18612, $19e74, + $18e32, $1bef4), + ($1f560, $1fab8, $1ea40, $1f530, $1fa9c, $1ea20, $1f518, $1fa8e, $1ea10, + $1f50c, $1ea08, $1f506, $1ea04, $1eb60, $1f5b8, $1fade, $1d640, $1eb30, + $1f59c, $1d620, $1eb18, $1f58e, $1d610, $1eb0c, $1d608, $1eb06, $1d604, + $1d760, $1ebb8, $1f5de, $1ae40, $1d730, $1eb9c, $1ae20, $1d718, $1eb8e, + $1ae10, $1d70c, $1ae08, $1d706, $1ae04, $1af60, $1d7b8, $1ebde, $15e40, + $1af30, $1d79c, $15e20, $1af18, $1d78e, $15e10, $1af0c, $15e08, $1af06, + $15f60, $1afb8, $1d7de, $15f30, $1af9c, $15f18, $1af8e, $15f0c, $15fb8, + $1afde, $15f9c, $15f8e, $1e940, $1f4b0, $1fa5c, $1e920, $1f498, $1fa4e, + $1e910, $1f48c, $1e908, $1f486, $1e904, $1e902, $1d340, $1e9b0, $1f4dc, + $1d320, $1e998, $1f4ce, $1d310, $1e98c, $1d308, $1e986, $1d304, $1d302, + $1a740, $1d3b0, $1e9dc, $1a720, $1d398, $1e9ce, $1a710, $1d38c, $1a708, + $1d386, $1a704, $1a702, $14f40, $1a7b0, $1d3dc, $14f20, $1a798, $1d3ce, + $14f10, $1a78c, $14f08, $1a786, $14f04, $14fb0, $1a7dc, $14f98, $1a7ce, + $14f8c, $14f86, $14fdc, $14fce, $1e8a0, $1f458, $1fa2e, $1e890, $1f44c, + $1e888, $1f446, $1e884, $1e882, $1d1a0, $1e8d8, $1f46e, $1d190, $1e8cc, + $1d188, $1e8c6, $1d184, $1d182, $1a3a0, $1d1d8, $1e8ee, $1a390, $1d1cc, + $1a388, $1d1c6, $1a384, $1a382, $147a0, $1a3d8, $1d1ee, $14790, $1a3cc, + $14788, $1a3c6, $14784, $14782, $147d8, $1a3ee, $147cc, $147c6, $147ee, + $1e850, $1f42c, $1e848, $1f426, $1e844, $1e842, $1d0d0, $1e86c, $1d0c8, + $1e866, $1d0c4, $1d0c2, $1a1d0, $1d0ec, $1a1c8, $1d0e6, $1a1c4, $1a1c2, + $143d0, $1a1ec, $143c8, $1a1e6, $143c4, $143c2, $143ec, $143e6, $1e828, + $1f416, $1e824, $1e822, $1d068, $1e836, $1d064, $1d062, $1a0e8, $1d076, + $1a0e4, $1a0e2, $141e8, $1a0f6, $141e4, $141e2, $1e814, $1e812, $1d034, + $1d032, $1a074, $1a072, $1e540, $1f2b0, $1f95c, $1e520, $1f298, $1f94e, + $1e510, $1f28c, $1e508, $1f286, $1e504, $1e502, $1cb40, $1e5b0, $1f2dc, + $1cb20, $1e598, $1f2ce, $1cb10, $1e58c, $1cb08, $1e586, $1cb04, $1cb02, + $19740, $1cbb0, $1e5dc, $19720, $1cb98, $1e5ce, $19710, $1cb8c, $19708, + $1cb86, $19704, $19702, $12f40, $197b0, $1cbdc, $12f20, $19798, $1cbce, + $12f10, $1978c, $12f08, $19786, $12f04, $12fb0, $197dc, $12f98, $197ce, + $12f8c, $12f86, $12fdc, $12fce, $1f6a0, $1fb58, $16bf0, $1f690, $1fb4c, + $169f8, $1f688, $1fb46, $168fc, $1f684, $1f682, $1e4a0, $1f258, $1f92e, + $1eda0, $1e490, $1fb6e, $1ed90, $1f6cc, $1f246, $1ed88, $1e484, $1ed84, + $1e482, $1ed82, $1c9a0, $1e4d8, $1f26e, $1dba0, $1c990, $1e4cc, $1db90, + $1edcc, $1e4c6, $1db88, $1c984, $1db84, $1c982, $1db82, $193a0, $1c9d8, + $1e4ee, $1b7a0, $19390, $1c9cc, $1b790, $1dbcc, $1c9c6, $1b788, $19384, + $1b784, $19382, $1b782, $127a0, $193d8, $1c9ee, $16fa0, $12790, $193cc, + $16f90, $1b7cc, $193c6, $16f88, $12784, $16f84, $12782, $127d8, $193ee, + $16fd8, $127cc, $16fcc, $127c6, $16fc6, $127ee, $1f650, $1fb2c, $165f8, + $1f648, $1fb26, $164fc, $1f644, $1647e, $1f642, $1e450, $1f22c, $1ecd0, + $1e448, $1f226, $1ecc8, $1f666, $1ecc4, $1e442, $1ecc2, $1c8d0, $1e46c, + $1d9d0, $1c8c8, $1e466, $1d9c8, $1ece6, $1d9c4, $1c8c2, $1d9c2, $191d0, + $1c8ec, $1b3d0, $191c8, $1c8e6, $1b3c8, $1d9e6, $1b3c4, $191c2, $1b3c2, + $123d0, $191ec, $167d0, $123c8, $191e6, $167c8, $1b3e6, $167c4, $123c2, + $167c2, $123ec, $167ec, $123e6, $167e6, $1f628, $1fb16, $162fc, $1f624, + $1627e, $1f622, $1e428, $1f216, $1ec68, $1f636, $1ec64, $1e422, $1ec62, + $1c868, $1e436, $1d8e8, $1c864, $1d8e4, $1c862, $1d8e2, $190e8, $1c876, + $1b1e8, $1d8f6, $1b1e4, $190e2, $1b1e2, $121e8, $190f6, $163e8, $121e4, + $163e4, $121e2, $163e2, $121f6, $163f6, $1f614, $1617e, $1f612, $1e414, + $1ec34, $1e412, $1ec32, $1c834, $1d874, $1c832, $1d872, $19074, $1b0f4, + $19072, $1b0f2, $120f4, $161f4, $120f2, $161f2, $1f60a, $1e40a, $1ec1a, + $1c81a, $1d83a, $1903a, $1b07a, $1e2a0, $1f158, $1f8ae, $1e290, $1f14c, + $1e288, $1f146, $1e284, $1e282, $1c5a0, $1e2d8, $1f16e, $1c590, $1e2cc, + $1c588, $1e2c6, $1c584, $1c582, $18ba0, $1c5d8, $1e2ee, $18b90, $1c5cc, + $18b88, $1c5c6, $18b84, $18b82, $117a0, $18bd8, $1c5ee, $11790, $18bcc, + $11788, $18bc6, $11784, $11782, $117d8, $18bee, $117cc, $117c6, $117ee, + $1f350, $1f9ac, $135f8, $1f348, $1f9a6, $134fc, $1f344, $1347e, $1f342, + $1e250, $1f12c, $1e6d0, $1e248, $1f126, $1e6c8, $1f366, $1e6c4, $1e242, + $1e6c2, $1c4d0, $1e26c, $1cdd0, $1c4c8, $1e266, $1cdc8, $1e6e6, $1cdc4, + $1c4c2, $1cdc2, $189d0, $1c4ec, $19bd0, $189c8, $1c4e6, $19bc8, $1cde6, + $19bc4, $189c2, $19bc2, $113d0, $189ec, $137d0, $113c8, $189e6, $137c8, + $19be6, $137c4, $113c2, $137c2, $113ec, $137ec, $113e6, $137e6, $1fba8, + $175f0, $1bafc, $1fba4, $174f8, $1ba7e, $1fba2, $1747c, $1743e, $1f328, + $1f996, $132fc, $1f768, $1fbb6, $176fc, $1327e, $1f764, $1f322, $1767e, + $1f762, $1e228, $1f116, $1e668, $1e224, $1eee8, $1f776, $1e222, $1eee4, + $1e662, $1eee2, $1c468, $1e236, $1cce8, $1c464, $1dde8, $1cce4, $1c462, + $1dde4, $1cce2, $1dde2, $188e8, $1c476, $199e8, $188e4, $1bbe8, $199e4, + $188e2, $1bbe4, $199e2, $1bbe2, $111e8, $188f6, $133e8, $111e4, $177e8, + $133e4, $111e2, $177e4, $133e2, $177e2, $111f6, $133f6, $1fb94, $172f8, + $1b97e, $1fb92, $1727c, $1723e, $1f314, $1317e, $1f734, $1f312, $1737e, + $1f732, $1e214, $1e634, $1e212, $1ee74, $1e632, $1ee72, $1c434, $1cc74, + $1c432, $1dcf4, $1cc72, $1dcf2, $18874, $198f4, $18872, $1b9f4, $198f2, + $1b9f2, $110f4, $131f4, $110f2, $173f4, $131f2, $173f2, $1fb8a, $1717c, + $1713e, $1f30a, $1f71a, $1e20a, $1e61a, $1ee3a, $1c41a, $1cc3a, $1dc7a, + $1883a, $1987a, $1b8fa, $1107a, $130fa, $171fa, $170be, $1e150, $1f0ac, + $1e148, $1f0a6, $1e144, $1e142, $1c2d0, $1e16c, $1c2c8, $1e166, $1c2c4, + $1c2c2, $185d0, $1c2ec, $185c8, $1c2e6, $185c4, $185c2, $10bd0, $185ec, + $10bc8, $185e6, $10bc4, $10bc2, $10bec, $10be6, $1f1a8, $1f8d6, $11afc, + $1f1a4, $11a7e, $1f1a2, $1e128, $1f096, $1e368, $1e124, $1e364, $1e122, + $1e362, $1c268, $1e136, $1c6e8, $1c264, $1c6e4, $1c262, $1c6e2, $184e8, + $1c276, $18de8, $184e4, $18de4, $184e2, $18de2, $109e8, $184f6, $11be8, + $109e4, $11be4, $109e2, $11be2, $109f6, $11bf6, $1f9d4, $13af8, $19d7e, + $1f9d2, $13a7c, $13a3e, $1f194, $1197e, $1f3b4, $1f192, $13b7e, $1f3b2, + $1e114, $1e334, $1e112, $1e774, $1e332, $1e772, $1c234, $1c674, $1c232, + $1cef4, $1c672, $1cef2, $18474, $18cf4, $18472, $19df4, $18cf2, $19df2, + $108f4, $119f4, $108f2, $13bf4, $119f2, $13bf2, $17af0, $1bd7c, $17a78, + $1bd3e, $17a3c, $17a1e, $1f9ca, $1397c, $1fbda, $17b7c, $1393e, $17b3e, + $1f18a, $1f39a, $1f7ba, $1e10a, $1e31a, $1e73a, $1ef7a, $1c21a, $1c63a, + $1ce7a, $1defa, $1843a, $18c7a, $19cfa, $1bdfa, $1087a, $118fa, $139fa, + $17978, $1bcbe, $1793c, $1791e, $138be, $179be, $178bc, $1789e, $1785e, + $1e0a8, $1e0a4, $1e0a2, $1c168, $1e0b6, $1c164, $1c162, $182e8, $1c176, + $182e4, $182e2, $105e8, $182f6, $105e4, $105e2, $105f6, $1f0d4, $10d7e, + $1f0d2, $1e094, $1e1b4, $1e092, $1e1b2, $1c134, $1c374, $1c132, $1c372, + $18274, $186f4, $18272, $186f2, $104f4, $10df4, $104f2, $10df2, $1f8ea, + $11d7c, $11d3e, $1f0ca, $1f1da, $1e08a, $1e19a, $1e3ba, $1c11a, $1c33a, + $1c77a, $1823a, $1867a, $18efa, $1047a, $10cfa, $11dfa, $13d78, $19ebe, + $13d3c, $13d1e, $11cbe, $13dbe, $17d70, $1bebc, $17d38, $1be9e, $17d1c, + $17d0e, $13cbc, $17dbc, $13c9e, $17d9e, $17cb8, $1be5e, $17c9c, $17c8e, + $13c5e, $17cde, $17c5c, $17c4e, $17c2e, $1c0b4, $1c0b2, $18174, $18172, + $102f4, $102f2, $1e0da, $1c09a, $1c1ba, $1813a, $1837a, $1027a, $106fa, + $10ebe, $11ebc, $11e9e, $13eb8, $19f5e, $13e9c, $13e8e, $11e5e, $13ede, + $17eb0, $1bf5c, $17e98, $1bf4e, $17e8c, $17e86, $13e5c, $17edc, $13e4e, + $17ece, $17e58, $1bf2e, $17e4c, $17e46, $13e2e, $17e6e, $17e2c, $17e26, + $10f5e, $11f5c, $11f4e, $13f58, $19fae, $13f4c, $13f46, $11f2e, $13f6e, + $13f2c, $13f26), + ($1abe0, $1d5f8, $153c0, $1a9f0, $1d4fc, $151e0, $1a8f8, $1d47e, $150f0, + $1a87c, $15078, $1fad0, $15be0, $1adf8, $1fac8, $159f0, $1acfc, $1fac4, + $158f8, $1ac7e, $1fac2, $1587c, $1f5d0, $1faec, $15df8, $1f5c8, $1fae6, + $15cfc, $1f5c4, $15c7e, $1f5c2, $1ebd0, $1f5ec, $1ebc8, $1f5e6, $1ebc4, + $1ebc2, $1d7d0, $1ebec, $1d7c8, $1ebe6, $1d7c4, $1d7c2, $1afd0, $1d7ec, + $1afc8, $1d7e6, $1afc4, $14bc0, $1a5f0, $1d2fc, $149e0, $1a4f8, $1d27e, + $148f0, $1a47c, $14878, $1a43e, $1483c, $1fa68, $14df0, $1a6fc, $1fa64, + $14cf8, $1a67e, $1fa62, $14c7c, $14c3e, $1f4e8, $1fa76, $14efc, $1f4e4, + $14e7e, $1f4e2, $1e9e8, $1f4f6, $1e9e4, $1e9e2, $1d3e8, $1e9f6, $1d3e4, + $1d3e2, $1a7e8, $1d3f6, $1a7e4, $1a7e2, $145e0, $1a2f8, $1d17e, $144f0, + $1a27c, $14478, $1a23e, $1443c, $1441e, $1fa34, $146f8, $1a37e, $1fa32, + $1467c, $1463e, $1f474, $1477e, $1f472, $1e8f4, $1e8f2, $1d1f4, $1d1f2, + $1a3f4, $1a3f2, $142f0, $1a17c, $14278, $1a13e, $1423c, $1421e, $1fa1a, + $1437c, $1433e, $1f43a, $1e87a, $1d0fa, $14178, $1a0be, $1413c, $1411e, + $141be, $140bc, $1409e, $12bc0, $195f0, $1cafc, $129e0, $194f8, $1ca7e, + $128f0, $1947c, $12878, $1943e, $1283c, $1f968, $12df0, $196fc, $1f964, + $12cf8, $1967e, $1f962, $12c7c, $12c3e, $1f2e8, $1f976, $12efc, $1f2e4, + $12e7e, $1f2e2, $1e5e8, $1f2f6, $1e5e4, $1e5e2, $1cbe8, $1e5f6, $1cbe4, + $1cbe2, $197e8, $1cbf6, $197e4, $197e2, $1b5e0, $1daf8, $1ed7e, $169c0, + $1b4f0, $1da7c, $168e0, $1b478, $1da3e, $16870, $1b43c, $16838, $1b41e, + $1681c, $125e0, $192f8, $1c97e, $16de0, $124f0, $1927c, $16cf0, $1b67c, + $1923e, $16c78, $1243c, $16c3c, $1241e, $16c1e, $1f934, $126f8, $1937e, + $1fb74, $1f932, $16ef8, $1267c, $1fb72, $16e7c, $1263e, $16e3e, $1f274, + $1277e, $1f6f4, $1f272, $16f7e, $1f6f2, $1e4f4, $1edf4, $1e4f2, $1edf2, + $1c9f4, $1dbf4, $1c9f2, $1dbf2, $193f4, $193f2, $165c0, $1b2f0, $1d97c, + $164e0, $1b278, $1d93e, $16470, $1b23c, $16438, $1b21e, $1641c, $1640e, + $122f0, $1917c, $166f0, $12278, $1913e, $16678, $1b33e, $1663c, $1221e, + $1661e, $1f91a, $1237c, $1fb3a, $1677c, $1233e, $1673e, $1f23a, $1f67a, + $1e47a, $1ecfa, $1c8fa, $1d9fa, $191fa, $162e0, $1b178, $1d8be, $16270, + $1b13c, $16238, $1b11e, $1621c, $1620e, $12178, $190be, $16378, $1213c, + $1633c, $1211e, $1631e, $121be, $163be, $16170, $1b0bc, $16138, $1b09e, + $1611c, $1610e, $120bc, $161bc, $1209e, $1619e, $160b8, $1b05e, $1609c, + $1608e, $1205e, $160de, $1605c, $1604e, $115e0, $18af8, $1c57e, $114f0, + $18a7c, $11478, $18a3e, $1143c, $1141e, $1f8b4, $116f8, $18b7e, $1f8b2, + $1167c, $1163e, $1f174, $1177e, $1f172, $1e2f4, $1e2f2, $1c5f4, $1c5f2, + $18bf4, $18bf2, $135c0, $19af0, $1cd7c, $134e0, $19a78, $1cd3e, $13470, + $19a3c, $13438, $19a1e, $1341c, $1340e, $112f0, $1897c, $136f0, $11278, + $1893e, $13678, $19b3e, $1363c, $1121e, $1361e, $1f89a, $1137c, $1f9ba, + $1377c, $1133e, $1373e, $1f13a, $1f37a, $1e27a, $1e6fa, $1c4fa, $1cdfa, + $189fa, $1bae0, $1dd78, $1eebe, $174c0, $1ba70, $1dd3c, $17460, $1ba38, + $1dd1e, $17430, $1ba1c, $17418, $1ba0e, $1740c, $132e0, $19978, $1ccbe, + $176e0, $13270, $1993c, $17670, $1bb3c, $1991e, $17638, $1321c, $1761c, + $1320e, $1760e, $11178, $188be, $13378, $1113c, $17778, $1333c, $1111e, + $1773c, $1331e, $1771e, $111be, $133be, $177be, $172c0, $1b970, $1dcbc, + $17260, $1b938, $1dc9e, $17230, $1b91c, $17218, $1b90e, $1720c, $17206, + $13170, $198bc, $17370, $13138, $1989e, $17338, $1b99e, $1731c, $1310e, + $1730e, $110bc, $131bc, $1109e, $173bc, $1319e, $1739e, $17160, $1b8b8, + $1dc5e, $17130, $1b89c, $17118, $1b88e, $1710c, $17106, $130b8, $1985e, + $171b8, $1309c, $1719c, $1308e, $1718e, $1105e, $130de, $171de, $170b0, + $1b85c, $17098, $1b84e, $1708c, $17086, $1305c, $170dc, $1304e, $170ce, + $17058, $1b82e, $1704c, $17046, $1302e, $1706e, $1702c, $17026, $10af0, + $1857c, $10a78, $1853e, $10a3c, $10a1e, $10b7c, $10b3e, $1f0ba, $1e17a, + $1c2fa, $185fa, $11ae0, $18d78, $1c6be, $11a70, $18d3c, $11a38, $18d1e, + $11a1c, $11a0e, $10978, $184be, $11b78, $1093c, $11b3c, $1091e, $11b1e, + $109be, $11bbe, $13ac0, $19d70, $1cebc, $13a60, $19d38, $1ce9e, $13a30, + $19d1c, $13a18, $19d0e, $13a0c, $13a06, $11970, $18cbc, $13b70, $11938, + $18c9e, $13b38, $1191c, $13b1c, $1190e, $13b0e, $108bc, $119bc, $1089e, + $13bbc, $1199e, $13b9e, $1bd60, $1deb8, $1ef5e, $17a40, $1bd30, $1de9c, + $17a20, $1bd18, $1de8e, $17a10, $1bd0c, $17a08, $1bd06, $17a04, $13960, + $19cb8, $1ce5e, $17b60, $13930, $19c9c, $17b30, $1bd9c, $19c8e, $17b18, + $1390c, $17b0c, $13906, $17b06, $118b8, $18c5e, $139b8, $1189c, $17bb8, + $1399c, $1188e, $17b9c, $1398e, $17b8e, $1085e, $118de, $139de, $17bde, + $17940, $1bcb0, $1de5c, $17920, $1bc98, $1de4e, $17910, $1bc8c, $17908, + $1bc86, $17904, $17902, $138b0, $19c5c, $179b0, $13898, $19c4e, $17998, + $1bcce, $1798c, $13886, $17986, $1185c, $138dc, $1184e, $179dc, $138ce, + $179ce, $178a0, $1bc58, $1de2e, $17890, $1bc4c, $17888, $1bc46, $17884, + $17882, $13858, $19c2e, $178d8, $1384c, $178cc, $13846, $178c6, $1182e, + $1386e, $178ee, $17850, $1bc2c, $17848, $1bc26, $17844, $17842, $1382c, + $1786c, $13826, $17866, $17828, $1bc16, $17824, $17822, $13816, $17836, + $10578, $182be, $1053c, $1051e, $105be, $10d70, $186bc, $10d38, $1869e, + $10d1c, $10d0e, $104bc, $10dbc, $1049e, $10d9e, $11d60, $18eb8, $1c75e, + $11d30, $18e9c, $11d18, $18e8e, $11d0c, $11d06, $10cb8, $1865e, $11db8, + $10c9c, $11d9c, $10c8e, $11d8e, $1045e, $10cde, $11dde, $13d40, $19eb0, + $1cf5c, $13d20, $19e98, $1cf4e, $13d10, $19e8c, $13d08, $19e86, $13d04, + $13d02, $11cb0, $18e5c, $13db0, $11c98, $18e4e, $13d98, $19ece, $13d8c, + $11c86, $13d86, $10c5c, $11cdc, $10c4e, $13ddc, $11cce, $13dce, $1bea0, + $1df58, $1efae, $1be90, $1df4c, $1be88, $1df46, $1be84, $1be82, $13ca0, + $19e58, $1cf2e, $17da0, $13c90, $19e4c, $17d90, $1becc, $19e46, $17d88, + $13c84, $17d84, $13c82, $17d82, $11c58, $18e2e, $13cd8, $11c4c, $17dd8, + $13ccc, $11c46, $17dcc, $13cc6, $17dc6, $10c2e, $11c6e, $13cee, $17dee, + $1be50, $1df2c, $1be48, $1df26, $1be44, $1be42, $13c50, $19e2c, $17cd0, + $13c48, $19e26, $17cc8, $1be66, $17cc4, $13c42, $17cc2, $11c2c, $13c6c, + $11c26, $17cec, $13c66, $17ce6, $1be28, $1df16, $1be24, $1be22, $13c28, + $19e16, $17c68, $13c24, $17c64, $13c22, $17c62, $11c16, $13c36, $17c76, + $1be14, $1be12, $13c14, $17c34, $13c12, $17c32, $102bc, $1029e, $106b8, + $1835e, $1069c, $1068e, $1025e, $106de, $10eb0, $1875c, $10e98, $1874e, + $10e8c, $10e86, $1065c, $10edc, $1064e, $10ece, $11ea0, $18f58, $1c7ae, + $11e90, $18f4c, $11e88, $18f46, $11e84, $11e82, $10e58, $1872e, $11ed8, + $18f6e, $11ecc, $10e46, $11ec6, $1062e, $10e6e, $11eee, $19f50, $1cfac, + $19f48, $1cfa6, $19f44, $19f42, $11e50, $18f2c, $13ed0, $19f6c, $18f26, + $13ec8, $11e44, $13ec4, $11e42, $13ec2, $10e2c, $11e6c, $10e26, $13eec, + $11e66, $13ee6, $1dfa8, $1efd6, $1dfa4, $1dfa2, $19f28, $1cf96, $1bf68, + $19f24, $1bf64, $19f22, $1bf62, $11e28, $18f16, $13e68, $11e24, $17ee8, + $13e64, $11e22, $17ee4, $13e62, $17ee2, $10e16, $11e36, $13e76, $17ef6, + $1df94, $1df92, $19f14, $1bf34, $19f12, $1bf32, $11e14, $13e34, $11e12, + $17e74, $13e32, $17e72, $1df8a, $19f0a, $1bf1a, $11e0a, $13e1a, $17e3a, + $1035c, $1034e, $10758, $183ae, $1074c, $10746, $1032e, $1076e, $10f50, + $187ac, $10f48, $187a6, $10f44, $10f42, $1072c, $10f6c, $10726, $10f66, + $18fa8, $1c7d6, $18fa4, $18fa2, $10f28, $18796, $11f68, $18fb6, $11f64, + $10f22, $11f62, $10716, $10f36, $11f76, $1cfd4, $1cfd2, $18f94, $19fb4, + $18f92, $19fb2, $10f14, $11f34, $10f12, $13f74, $11f32, $13f72, $1cfca, + $18f8a, $19f9a, $10f0a, $11f1a, $13f3a, $103ac, $103a6, $107a8, $183d6, + $107a4, $107a2, $10396, $107b6, $187d4, $187d2, $10794, $10fb4, $10792, + $10fb2, $1c7ea)); + +type + TStPDF417TextCompactionMode = (cmAlpha, cmLower, cmMixed, cmPunctuation, + cmNone); + TStPDF417TextCompactionModes = set of TStPDF417TextCompactionMode; + + TStPDF417TextCompactionData = record + Value : Integer; + Mode : TStPDF417TextCompactionModes; + end; + +const + TStPDF417TextCompaction : array [0..127] of TStPDF417TextCompactionData = + ((Value : -1; Mode : []), { 000 } + (Value : -1; Mode : []), { 001 } + (Value : -1; Mode : []), { 002 } + (Value : -1; Mode : []), { 003 } + (Value : -1; Mode : []), { 004 } + (Value : -1; Mode : []), { 005 } + (Value : -1; Mode : []), { 006 } + (Value : -1; Mode : []), { 007 } + (Value : -1; Mode : []), { 008 } + (Value : 12; Mode : [cmMixed, cmPunctuation]), { 009 } + (Value : 15; Mode : [cmPunctuation]), { 010 } + (Value : -1; Mode : []), { 011 } + (Value : -1; Mode : []), { 012 } + (Value : 11; Mode : [cmMixed, cmPunctuation]), { 013 } + (Value : -1; Mode : []), { 014 } + (Value : -1; Mode : []), { 015 } + (Value : -1; Mode : []), { 016 } + (Value : -1; Mode : []), { 017 } + (Value : -1; Mode : []), { 018 } + (Value : -1; Mode : []), { 019 } + (Value : -1; Mode : []), { 020 } + (Value : -1; Mode : []), { 021 } + (Value : -1; Mode : []), { 022 } + (Value : -1; Mode : []), { 023 } + (Value : -1; Mode : []), { 024 } + (Value : -1; Mode : []), { 025 } + (Value : -1; Mode : []), { 026 } + (Value : -1; Mode : []), { 027 } + (Value : -1; Mode : []), { 028 } + (Value : -1; Mode : []), { 029 } + (Value : -1; Mode : []), { 030 } + (Value : -1; Mode : []), { 031 } + (Value : 26; Mode : [cmAlpha, cmLower, cmMixed]), { 032 } + (Value : 10; Mode : [cmPunctuation]), { 033 } + (Value : 20; Mode : [cmPunctuation]), { 034 } + (Value : 15; Mode : [cmMixed]), { 035 } + (Value : 18; Mode : [cmMixed, cmPunctuation]), { 036 } + (Value : 21; Mode : [cmMixed]), { 037 } + (Value : 10; Mode : [cmMixed]), { 038 } + (Value : 28; Mode : [cmPunctuation]), { 039 } + (Value : 23; Mode : [cmPunctuation]), { 040 } + (Value : 24; Mode : [cmPunctuation]), { 041 } + (Value : 22; Mode : [cmMixed, cmPunctuation]), { 042 } + (Value : 20; Mode : [cmMixed]), { 043 } + (Value : 13; Mode : [cmMixed, cmPunctuation]), { 044 } + (Value : 16; Mode : [cmMixed, cmPunctuation]), { 045 } + (Value : 17; Mode : [cmMixed, cmPunctuation]), { 046 } + (Value : 19; Mode : [cmMixed, cmPunctuation]), { 047 } + (Value : 0; Mode : [cmMixed]), { 048 } + (Value : 1; Mode : [cmMixed]), { 049 } + (Value : 2; Mode : [cmMixed]), { 050 } + (Value : 3; Mode : [cmMixed]), { 051 } + (Value : 4; Mode : [cmMixed]), { 052 } + (Value : 5; Mode : [cmMixed]), { 053 } + (Value : 6; Mode : [cmMixed]), { 054 } + (Value : 7; Mode : [cmMixed]), { 055 } + (Value : 8; Mode : [cmMixed]), { 056 } + (Value : 9; Mode : [cmMixed]), { 057 } + (Value : 14; Mode : [cmMixed, cmPunctuation]), { 058 } + (Value : 0; Mode : [cmPunctuation]), { 059 } + (Value : 1; Mode : [cmPunctuation]), { 060 } + (Value : 23; Mode : [cmMixed]), { 061 } + (Value : 2; Mode : [cmPunctuation]), { 062 } + (Value : 25; Mode : [cmPunctuation]), { 063 } + (Value : 3; Mode : [cmPunctuation]), { 064 } + (Value : 0; Mode : [cmAlpha]), { 065 } + (Value : 1; Mode : [cmAlpha]), { 066 } + (Value : 2; Mode : [cmAlpha]), { 067 } + (Value : 3; Mode : [cmAlpha]), { 068 } + (Value : 4; Mode : [cmAlpha]), { 069 } + (Value : 5; Mode : [cmAlpha]), { 070 } + (Value : 6; Mode : [cmAlpha]), { 071 } + (Value : 7; Mode : [cmAlpha]), { 072 } + (Value : 8; Mode : [cmAlpha]), { 073 } + (Value : 9; Mode : [cmAlpha]), { 074 } + (Value : 10; Mode : [cmAlpha]), { 075 } + (Value : 11; Mode : [cmAlpha]), { 076 } + (Value : 12; Mode : [cmAlpha]), { 077 } + (Value : 13; Mode : [cmAlpha]), { 078 } + (Value : 14; Mode : [cmAlpha]), { 079 } + (Value : 15; Mode : [cmAlpha]), { 080 } + (Value : 16; Mode : [cmAlpha]), { 081 } + (Value : 17; Mode : [cmAlpha]), { 082 } + (Value : 18; Mode : [cmAlpha]), { 083 } + (Value : 19; Mode : [cmAlpha]), { 084 } + (Value : 20; Mode : [cmAlpha]), { 085 } + (Value : 21; Mode : [cmAlpha]), { 086 } + (Value : 22; Mode : [cmAlpha]), { 087 } + (Value : 23; Mode : [cmAlpha]), { 088 } + (Value : 24; Mode : [cmAlpha]), { 089 } + (Value : 25; Mode : [cmAlpha]), { 090 } + (Value : 4; Mode : [cmPunctuation]), { 091 } + (Value : 5; Mode : [cmPunctuation]), { 092 } + (Value : 6; Mode : [cmPunctuation]), { 093 } + (Value : 24; Mode : [cmMixed]), { 094 } + (Value : 7; Mode : [cmPunctuation]), { 095 } + (Value : 8; Mode : [cmPunctuation]), { 096 } + (Value : 0; Mode : [cmLower]), { 097 } + (Value : 1; Mode : [cmLower]), { 098 } + (Value : 2; Mode : [cmLower]), { 099 } + (Value : 3; Mode : [cmLower]), { 100 } + (Value : 4; Mode : [cmLower]), { 101 } + (Value : 5; Mode : [cmLower]), { 102 } + (Value : 6; Mode : [cmLower]), { 103 } + (Value : 7; Mode : [cmLower]), { 104 } + (Value : 8; Mode : [cmLower]), { 105 } + (Value : 9; Mode : [cmLower]), { 106 } + (Value : 10; Mode : [cmLower]), { 107 } + (Value : 11; Mode : [cmLower]), { 108 } + (Value : 12; Mode : [cmLower]), { 109 } + (Value : 13; Mode : [cmLower]), { 110 } + (Value : 14; Mode : [cmLower]), { 111 } + (Value : 15; Mode : [cmLower]), { 112 } + (Value : 16; Mode : [cmLower]), { 113 } + (Value : 17; Mode : [cmLower]), { 114 } + (Value : 18; Mode : [cmLower]), { 115 } + (Value : 19; Mode : [cmLower]), { 116 } + (Value : 20; Mode : [cmLower]), { 117 } + (Value : 21; Mode : [cmLower]), { 118 } + (Value : 22; Mode : [cmLower]), { 119 } + (Value : 23; Mode : [cmLower]), { 120 } + (Value : 24; Mode : [cmLower]), { 121 } + (Value : 25; Mode : [cmLower]), { 122 } + (Value : 26; Mode : [cmPunctuation]), { 123 } + (Value : 21; Mode : [cmPunctuation]), { 124 } + (Value : 27; Mode : [cmPunctuation]), { 125 } + (Value : 9; Mode : [cmPunctuation]), { 126 } + (Value : -1; Mode : [])); { 127 } + +{ TStMaxiCode types and constants } + +type + TStMaxiCodeCodeSet = (csCodeSetA, csCodeSetB, csCodeSetC, csCodeSetD, + csCodeSetE, csNone); + +const + StMaxiCodeCodeSets : array [csCodeSetA..csCodeSetE] of + array [0..255] of ShortInt = + { csCodeSetA } + {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} + ((-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {000} + -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, {010} + -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, {020} + 30, -1, 32, 33, 34, 35, 36, 37, 38, 39, {030} + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, {040} + 50, 51, 52, 53, 54, 55, 56, 57, 58, -1, {050} + -1, -1, -1, -1, -1, 1, 2, 3, 4, 5, {060} + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, {070} + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, {080} + 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, {090} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {100} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {110} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {120} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {130} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {140} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {150} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {160} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {170} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {180} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {190} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {200} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {210} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {220} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {230} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {240} + -1, -1, -1, -1, -1, -1), {250} + { csCodeSetB } + {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} + (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {000} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {010} + -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, {020} + 30, -1, 47, 53, -1, -1, -1, -1, -1, -1, {030} + -1, -1, -1, -1, 48, 49, 50, -1, -1, -1, {040} + -1, -1, -1, -1, -1, -1, -1, -1, 51, 37, {050} + 38, 39, 40, 41, 52, -1, -1, -1, -1, -1, {060} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {070} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {080} + -1, 42, 43, 44, 45, 46, 0, 1, 2, 3, {090} + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, {100} + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, {110} + 24, 25, 26, 32, 54, 34, 35, 36, -1, -1, {120} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {130} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {140} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {150} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {160} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {170} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {180} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {190} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {200} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {210} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {220} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {230} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {240} + -1, -1, -1, -1, -1, -1), {250} + { csCodeSetC } + {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} + (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {000} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {010} + -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, {020} + 30, -1, 59, -1, -1, -1, -1, -1, -1, -1, {030} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {040} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {050} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {060} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {070} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {080} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {090} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {100} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {110} + -1, -1, -1, -1, -1, -1, -1, -1, 48, 49, {120} + 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, {130} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {140} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {150} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {160} + 37, -1, 38, -1, -1, -1, -1, 39, 40, 41, {170} + -1, 42, -1, -1, -1, 43, 44, -1, 45, 46, {180} + 47, -1, 0, 1, 2, 3, 4, 5, 6, 7, {190} + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, {200} + 18, 19, 20, 21, 22, 23, 24, 25, 26, 32, {210} + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, {220} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {230} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {240} + -1, -1, -1, -1, -1, -1), {250} + { csCodeSetD } + {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} + (-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {000} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {010} + -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, {020} + 30, -1, 59, -1, -1, -1, -1, -1, -1, -1, {030} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {040} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {050} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {060} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {070} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {080} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {090} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {100} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {110} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {120} + -1, -1, -1, -1, -1, -1, -1, -1, 47, 48, {130} + 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, {140} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {150} + -1, 37, -1, -1, -1, -1, -1, -1, 38, -1, {160} + -1, 39, -1, -1, -1, 40, 41, -1, -1, -1, {170} + 42, -1, -1, 43, 44, -1, -1, 45, -1, -1, {180} + -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, {190} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {200} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {210} + -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, {220} + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, {230} + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, {240} + 26, 32, 33, 34, 35, 36), {250} + { csCodeSetE } + {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} + ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, {000} + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, {010} + 20, 21, 22, 23, 24, 25, 26, 30, 32, 33, {020} + 34, 35, 59, -1, -1, -1, -1, -1, -1, -1, {030} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {040} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {050} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {060} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {070} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {080} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {090} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {100} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {110} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {120} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {130} + -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, {140} + 49, 50, 51, 52, 53, 54, 55, 56, 57, 36, {150} + 37, -1, 38, 39, 40, 41, 42, 43, -1, 44, {160} + -1, -1, -1, 45, 46, -1, -1, -1, -1, -1, {170} + -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, {180} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {190} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {200} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {210} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {220} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {230} + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, {240} + -1, -1, -1, -1, -1, -1)); {250} + +{ TStCustom2DBarcode } + +constructor TStCustom2DBarcode.Create (AOwner : TComponent); +begin + inherited Create (AOwner); + + FBitmap := TBitmap.Create; + + FBarWidth := 2; + FBarHeight := 0; + FBackgroundColor := clWhite; + FExtendedSyntax := True; + FQuietZone := 8; + FAlignment := taCenter; + FCaptionLayout := tlBottom; + Width := 329; + Height := 50; + Color := clBlack; + FECCLevel := 2; + FRelativeBarHeight := False; + FBarHeightToWidth := 4; + FBarHeight := 2; + FCaption := ''; + FCode := ''; + FECCLevel := 0; +end; + +destructor TStCustom2DBarcode.Destroy; +begin + FBitmap.Free; + + inherited Destroy; +end; + +procedure TStCustom2DBarcode.CopyToClipboard; +begin + CopyToClipboardRes (0, 0); +end; + +procedure TStCustom2DBarcode.CopyToClipboardRes (ResX : Integer; + ResY : Integer); +var + {$IFNDEF FPC} + MetaFile : TMetaFile; + MetaFileCanvas : TMetaFileCanvas; + {$ENDIF} + RenderBMP : TBitmap; + SizeX : Integer; + SizeY : Integer; + +begin + Clipboard.Clear; + Clipboard.Open; + try + RenderBmp := TBitmap.Create; + try + RenderToResolution (RenderBmp, ResX, ResY, SizeX, SizeY); + Clipboard.Assign (RenderBmp); + + {$IFNDEF FPC} + {metafile} + MetaFile := TMetaFile.Create; + try + MetaFileCanvas := TMetaFileCanvas.Create (MetaFile, 0); + try + MetaFile.Enhanced := True; + MetaFile.Width := ClientWidth; + MetaFile.Height := ClientHeight; + MetaFileCanvas.Draw (0, 0, RenderBmp); + finally + MetaFileCanvas.Free; + end; + Clipboard.Assign (MetaFile); + finally + MetaFile.Free; + end; + {$ENDIF} + finally + RenderBmp.Free; + end; + finally + Clipboard.Close; + end; +end; + +procedure TStCustom2DBarcode.GenerateBarcodeBitmap (BCWidth : Integer; + BCHeight : Integer); +var + TextHeight : Integer; + TextWidth : Integer; + XPos : Integer; + YPos : Integer; + TopOffset : Integer; + BottomOffset : Integer; + BarCodeHeight : Integer; + BarCodeWidth : Integer; + RWidthOffset : Integer; + LWidthOffset : Integer; + PaintHeight : Integer; + +begin + { Initialize the canvas } + FBitmap.Width := BCWidth; + FBitmap.Height := BCHeight; + FBitmap.Canvas.Pen.Color := Color; + FBitmap.Canvas.Brush.Color := BackgroundColor; + FBitmap.Canvas.FillRect (Rect (0, 0, BCWidth, BCHeight)); + FBitmap.Canvas.Brush.Color := Color; + + { Calculate the size of the caption } + FBitmap.Canvas.Font.Assign (Font); + TextHeight := FBitmap.Canvas.TextHeight ('Yg0'); + TextWidth := FBitmap.Canvas.TextWidth (Caption); + + { determine x position of the caption } + XPos := 0; + case FAlignment of + taLeftJustify : + XPos := 0; + taRightJustify : + if BCWidth - TextWidth > 0 then + XPos := BCWidth - TextWidth + else + XPos := 0; + taCenter : + if BCWidth - TextWidth > 0 then + XPos := BCWidth div 2 - TextWidth div 2 + else + XPos := 0; + end; + + { determine the y position of the caption. In addition, determine offsets + for the barcode painting. } + TopOffset := 0; + BottomOffset := 0; + YPos := 0; + case FCaptionLayout of + tlBottom : + begin + if BCHeight - 2 - TextHeight > 0 then + YPos := BCHeight - 2 - TextHeight + else + YPos := 0; + if Caption <> '' then + BottomOffset := TextHeight + 4; + end; + tlTop : + begin + YPos := 0; + if Caption <> '' then + TopOffset := TextHeight + 4; + end; + tlCenter : + if BCHeight - TextHeight > 0 then + YPos := BCHeight div 2 - TextHeight div 2 + else + YPos := 0; + end; + + { determine the size of the barcode and calculate the rectangle the + barcode should be painted in. Take into account the size of the + caption (and it's existance), and the quiet zone.} + PaintHeight := BCHeight - QuietZone * 2 - BottomOffset - TopOffset; + BarCodeHeight := CalculateBarCodeHeight (PaintHeight); + BarCodeWidth := CalculateBarCodeWidth (BCWidth); + if BarCodeHeight < PaintHeight then begin + Inc (BottomOffset, (PaintHeight - BarCodeHeight) div 2); + Inc (TopOffset, (PaintHeight - BarCodeHeight) div 2); + end; + + { Position the barcode horizontally } + LWidthOffset := QuietZone; + RWidthOffset := QuietZone; + if BarCodeWidth < BCWidth - QuietZone * 2 then + case Alignment of + taLeftJustify : + begin + LWidthOffset := QuietZone; + RWidthOffset := BCWidth - BarCodeWidth - QuietZone; + end; + taRightJustify : + begin + RWidthOffset := QuietZone; + LWidthOffset := BCWidth - BarCodeWidth - QuietZone; + end; + taCenter : + begin + LWidthOffset := (BCWidth - BarCodeWidth) div 2; + RWidthOffset := (BCWidth - BarCodeWidth) div 2; + end; + end; + + { Save the barcode rectangle } + FBarCodeRect := Rect (LWidthOffset, + QuietZone + TopOffset, + BCWidth - RWidthOffset, + BCHeight - QuietZone - BottomOffset); + { Draw the barcode } + DrawBarcode; + + FBitmap.Canvas.Brush.Color := BackgroundColor; + { Draw the caption } + FBitmap.Canvas.TextOut (XPos, YPos, Caption); +end; + +function TStCustom2DBarcode.GetBarCodeHeight : Integer; +begin + Result := CalculateBarCodeHeight (Height); +end; + +function TStCustom2DBarcode.GetBarCodeWidth : Integer; +begin + Result := CalculateBarCodeWidth (Width); +end; + +procedure TStCustom2DBarcode.GetCurrentResolution (var ResX : Integer; + var ResY : Integer); +begin + ResX := GetDeviceCaps (FBitmap.Canvas.Handle, LOGPIXELSX); + ResY := GetDeviceCaps (FBitmap.Canvas.Handle, LOGPIXELSY); +end; + +function TStCustom2DBarcode.GetVersion : string; +begin + Result := StVersionStr; +end; + +procedure TStCustom2DBarcode.Paint; +begin + GenerateBarcodeBitmap (Width, Height); + Canvas.CopyRect (Rect (0, 0, Width, Height), + FBitmap.Canvas, + Rect (0, 0, Width, Height)); +end; + +procedure TStCustom2DBarcode.PaintToCanvas (ACanvas : TCanvas; + Position : TPoint); +begin + PaintToDC (ACanvas.Handle, Position); +end; + +procedure TStCustom2DBarcode.PaintToCanvasRes (ACanvas : TCanvas; + Position : TPoint; + ResX : Integer; + ResY : Integer); +begin + PaintToDCRes (ACanvas.Handle, Position, ResX, ResY); +end; + +procedure TStCustom2DBarcode.PaintToCanvasSize (ACanvas : TCanvas; + X, Y, H : Double); +var + PixelsPerInchX : Integer; + PixelsPerInchY : Integer; + +begin + {get some information about this device context} + PixelsPerInchX := GetDeviceCaps (ACanvas.Handle, LOGPIXELSX); + PixelsPerInchY := GetDeviceCaps (ACanvas.Handle, LOGPIXELSY); + + PaintToCanvasRes (ACanvas, + Point (Round (PixelsPerInchX * X), + Round (PixelsPerInchY * Y)), + Round (PixelsPerInchX * H), + Round (PixelsPerInchY * H)); +end; + +procedure TStCustom2DBarcode.PaintToDC (DC : hDC; Position : TPoint); +var + NewResX : Integer; + NewResY : Integer; + +begin + NewResX := GetDeviceCaps (DC, LOGPIXELSX); + NewResY := GetDeviceCaps (DC, LOGPIXELSY); + PaintToDCRes (DC, Position, NewResX, NewResY); +end; + +procedure TStCustom2DBarcode.PaintToDCRes (DC : hDC; Position : TPoint; + ResX : Integer; ResY : Integer); +var + ACanvas : TCanvas; + R1 : TRect; + R2 : TRect; + RenderBmp : TBitmap; + SizeX : Integer; + SizeY : Integer; + +begin + ACanvas := TCanvas.Create; + ACanvas.Handle := DC; + try + RenderBmp := TBitmap.Create; + try + {this is necessary because of a Delphi buglet} + RenderBmp.Canvas.Font.PixelsPerInch := ResY; + {use our font} + RenderBmp.Canvas.Font := Font; + + RenderToResolution (RenderBmp, ResX, ResY, SizeX, SizeY); + R1 := Rect (0, 0, RenderBmp.Width, RenderBmp.Height); + R2 := Rect (Position.X, Position.Y, + RenderBmp.Width + Position.X, + RenderBmp.Height + Position.Y); + + ACanvas.CopyRect (R2, RenderBmp.Canvas, R1); + finally + RenderBmp.Free; + end; + finally + ACanvas.Free; + end; +end; + +procedure TStCustom2DBarcode.PaintToPrinterCanvas (ACanvas : TCanvas; + Position : TPoint); +begin + PaintToPrinterDC (ACanvas.Handle, Position); +end; + +procedure TStCustom2DBarcode.PaintToPrinterCanvasRes (ACanvas : TCanvas; + Position : TPoint; + ResX : Integer; + ResY : Integer); +begin + PaintToPrinterDCRes (ACanvas.Handle, Position, ResX, ResY); +end; + +procedure TStCustom2DBarcode.PaintToPrinterCanvasSize (ACanvas : TCanvas; + X, Y, H : Double); +var + PixelsPerInchX : Integer; + PixelsPerInchY : Integer; + +begin + {get some information about this device context} + PixelsPerInchX := GetDeviceCaps (ACanvas.Handle, LOGPIXELSX); + PixelsPerInchY := GetDeviceCaps (ACanvas.Handle, LOGPIXELSY); + + PaintToPrinterCanvasRes (ACanvas, + Point (Round (PixelsPerInchX * X), + Round (PixelsPerInchY * Y)), + Round (PixelsPerInchX * H), + Round (PixelsPerInchY * H)); +end; + +procedure TStCustom2DBarcode.PaintToPrinterDC (DC : hDC; Position : TPoint); +var + NewResX : Integer; + NewResY : Integer; + +begin + NewResX := GetDeviceCaps (DC, LOGPIXELSX); + NewResY := GetDeviceCaps (DC, LOGPIXELSY); + PaintToPrinterDCRes (DC, Position, NewResX, NewResY); +end; + +procedure TStCustom2DBarcode.PaintToPrinterDCRes (DC : hDC; + Position : TPoint; + ResX : Integer; + ResY : Integer); +var + ACanvas : TCanvas; + R2 : TRect; + Info : PBitMapInfo; + InfoSize : DWORD; + ImageSize : DWORD; + Image : Pointer; + RenderBmp : TBitmap; + SizeX : Integer; + SizeY : Integer; + +begin + (* ---------- to do: fix me for Lazarus --------- + ACanvas := TCanvas.Create; + ACanvas.Handle := DC; + try + RenderBmp := TBitmap.Create; + try + {this is necessary because of a Delphi buglet} + RenderBmp.Canvas.Font.PixelsPerInch := ResY; + {use our font} + RenderBmp.Canvas.Font.Assign (Font); + + RenderToResolution (RenderBmp, ResX, ResY, SizeX, SizeY); + R2 := Rect (Position.X, Position.Y, + SizeX + Position.X, + SizeY + Position.Y); + + {Delphi does not allow a simple Canvas.CopyRect to the printer Canvas} + with RenderBmp do begin + GetDIBSizes (Handle, InfoSize, ImageSize); + GetMem (Info, InfoSize); + try + GetMem (Image, ImageSize); + try + GetDIB (Handle, Palette, Info^, Image^); + with Info^.bmiHeader do begin + StretchDIBits (ACanvas.Handle, + R2.Left, R2.Top, SizeX, SizeY, + 0, 0, biWidth, biHeight, + Image, Info^, DIB_RGB_COLORS, SRCCOPY); + end; + finally + FreeMem (Image, ImageSize) + end; + finally + FreeMem (Info, InfoSize); + end; + end; + finally + RenderBmp.Free; + end; + finally + ACanvas.Free; + end; + *) +end; + +procedure TStCustom2DBarcode.SaveToFile (const FileName : string); +begin + GenerateBarcodeBitmap (Width, Height); + FBitmap.SaveToFile (FileName); +end; + +procedure TStCustom2DBarcode.SaveToFileRes (const FileName : string; + ResX : Integer; ResY : Integer); +var + RenderBmp : TBitmap; + SizeX : Integer; + SizeY : Integer; + +begin + RenderBmp := TBitmap.Create; + try + RenderToResolution (RenderBmp, ResX, ResY, SizeX, SizeY); + RenderBmp.SaveToFile (FileName); + finally + RenderBmp.Free; + end; +end; + +procedure TStCustom2DBarcode.SetAlignment (const v : TAlignment); +var + OldAlignment : TAlignment; + +begin + if v <> FAlignment then begin + OldAlignment := FAlignment; + try + FAlignment := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FAlignment := OldAlignment; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetBackgroundColor (const v : TColor); +var + OldBackgroundColor : TColor; + +begin + if v <> FBackgroundColor then begin + OldBackgroundColor := FBackgroundColor; + try + FBackgroundColor := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FBackgroundColor := OldBackgroundColor; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetBarHeight (const v : Integer); +var + OldBarHeight : Integer; + +begin + if v <> FBarHeight then begin + OldBarHeight := FBarHeight; + try + FBarHeight := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FBarHeight := OldBarHeight; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetBarHeightToWidth (const v : Integer); +var + OldBarHeightToWidth : Integer; + +begin + if v <> FBarHeightToWidth then begin + if v < 0 then + raise E2DBarcodeError.Create (StEBadBarHeightToWidth); + OldBarHeightToWidth := FBarHeightToWidth; + try + FBarHeightToWidth := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FBarHeightToWidth := OldBarHeightToWidth; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetBarWidth (const v : Integer); +var + OldBarWidth : Integer; + +begin + if v <> FBarWidth then begin + OldBarWidth := FBarWidth; + try + FBarWidth := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FBarWidth := OldBarWidth; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetBitmap (const v : TBitmap); +begin + FBitmap.Assign (v); + Invalidate; +end; + +procedure TStCustom2DBarcode.SetCaption (const v : string); +var + OldCaption : string; + +begin + if v <> FCaption then begin + OldCaption := FCaption; + try + FCaption := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FCaption := OldCaption; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetCaptionLayout (const v : TTextLayout); +var + OldCaptionLayout : TTextLayout; + +begin + if v <> FCaptionLayout then begin + OldCaptionLayout := FCaptionLayout; + try + FCaptionLayout := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FCaptionLayout := OldCaptionLayout; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetCode (const v : string); +var + OldCode : string; + +begin + if v <> FCode then begin + OldCode := FCode; + try + FCode := v; + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FCode := OldCode; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetECCLevel (const v : Integer); +var + OldECCLevel : Integer; + +begin + if v <> FECCLevel then begin + OldECCLevel := FECCLevel; + try + FECCLevel := v; + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FECCLevel := OldECCLevel; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetExtendedSyntax (const v : Boolean); +var + OldExtendedSyntax : Boolean; + +begin + if v <> FExtendedSyntax then begin + OldExtendedSyntax := FExtendedSyntax; + try + FExtendedSyntax := v; + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FExtendedSyntax := OldExtendedSyntax; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetQuietZone (const v : Integer); +var + OldQuietZone : Integer; + +begin + if v <> FQuietZone then begin + if (v < 0) then + raise E2DBarcodeError.Create (StEBadQuietZone); + OldQuietZone := FQuietZone; + try + FQuietZone := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FQuietZone := OldQuietZone; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetRelativeBarHeight (const v : Boolean); +var + OldRelativeBarHeight : Boolean; + +begin + if v <> FRelativeBarHeight then begin + OldRelativeBarHeight := FRelativeBarHeight; + try + FRelativeBarHeight := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FRelativeBarHeight := OldRelativeBarHeight; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStCustom2DBarcode.SetVersion(const Value : string); +begin +end; + +{ TStPDF417Barcode } + +constructor TStPDF417Barcode.Create (AOwner : TComponent); +begin + inherited Create (AOwner); + + FNumCodewords := 1; + FTruncated := False; + FHighlight := False; + FECCLevel := -1; + FNumRows := 0; + FNumColumns := 0; + FTotalCodewords := FNumRows * FNumColumns; + FUsedCodewords := 0; + FUsedECCCodewords := 0; + FFreeCodewords := FTotalCodewords; + Width := 273; + Height := 81; + + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); +end; + +procedure TStPDF417Barcode.AddCodeword (Value : Word); +begin + FCodewords[FNumCodewords] := Value; + Inc (FNumCodewords); +end; + +function TStPDF417Barcode.CalculateBarCodeWidth ( + PaintableWidth : Integer) : Integer; +var + XSize : Integer; + YSize : Integer; + +begin + CalculateSize (XSize, YSize); + if Truncated then + Result := (XSize + 2) * 17 * BarWidth + BarWidth + else + Result := (XSize + 4) * 17 * BarWidth + BarWidth; +end; + +function TStPDF417Barcode.CalculateBarCodeHeight ( + PaintableHeight : Integer) : Integer; +var + XSize : Integer; + YSize : Integer; + +begin + CalculateSize (XSize, YSize); + if RelativeBarHeight then + Result := PaintableHeight + else if BarHeightToWidth <> 0 then + Result := (BarHeightToWidth * BarWidth) * YSize + else + Result := BarHeight * YSize; +end; + +procedure TStPDF417Barcode.CalculateECC (NumCodewords : Integer; + ECCLen : Integer); + +const + StMods : array [0..64] of array [0..64] of Integer = + (( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (917, 27, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (890, 351, 200, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (809, 723, 568, 522, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (566, 155, 460, 919, 427, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (766, 17, 803, 19, 285, 861, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (437, 691, 784, 597, 537, 925, 76, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (379, 428, 653, 646, 284, 436, 308, 237, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (205, 441, 501, 362, 289, 257, 622, 527, + 567, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (612, 266, 691, 818, 841, 826, 244, 64, + 457, 377, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (904, 602, 327, 68, 15, 213, 825, 708, + 565, 45, 462, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (851, 69, 7, 388, 127, 347, 684, 646, + 201, 757, 864, 597, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (692, 394, 184, 204, 678, 592, 322, 583, + 606, 384, 342, 713, 764, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (215, 105, 833, 691, 915, 478, 354, 274, + 286, 241, 187, 154, 677, 669, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (642, 868, 147, 575, 550, 74, 80, 5, + 230, 664, 904, 109, 476, 829, 460, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 65, 176, 42, 295, 428, 442, 116, 295, + 132, 801, 524, 599, 755, 232, 562, 274, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (192, 70, 98, 55, 733, 916, 510, 163, + 437, 843, 61, 259, 650, 430, 298, 115, + 425, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (573, 760, 756, 233, 321, 560, 202, 312, + 297, 120, 739, 275, 855, 37, 624, 315, + 577, 279, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (787, 754, 821, 371, 17, 508, 201, 806, + 177, 506, 407, 491, 249, 923, 181, 75, + 170, 200, 250, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (500, 632, 880, 710, 375, 274, 258, 717, + 176, 802, 109, 736, 540, 64, 45, 152, + 12, 647, 448, 712, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (568, 259, 193, 165, 347, 691, 310, 610, + 624, 693, 763, 716, 422, 553, 681, 425, + 129, 534, 781, 519, 108, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (772, 6, 76, 519, 563, 875, 66, 678, + 578, 716, 927, 296, 633, 244, 155, 928, + 432, 838, 95, 55, 78, 665, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (455, 538, 32, 581, 473, 772, 462, 194, + 251, 503, 631, 1, 630, 247, 843, 101, + 749, 457, 143, 597, 294, 93, 78, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (433, 747, 273, 806, 697, 585, 200, 249, + 628, 555, 713, 54, 608, 322, 54, 135, + 385, 701, 308, 238, 166, 128, 819, 142, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (367, 39, 208, 439, 454, 104, 608, 55, + 916, 912, 314, 375, 760, 141, 169, 287, + 765, 374, 492, 348, 251, 320, 732, 899, + 847, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (169, 764, 847, 131, 858, 325, 454, 441, + 245, 699, 893, 446, 830, 159, 121, 269, + 608, 331, 760, 477, 93, 788, 544, 887, + 284, 443, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (504, 710, 383, 531, 151, 694, 636, 175, + 269, 93, 21, 463, 671, 438, 433, 857, + 610, 560, 165, 531, 100, 357, 688, 114, + 149, 825, 694, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (580, 925, 461, 840, 560, 93, 427, 203, + 563, 99, 586, 201, 557, 339, 277, 321, + 712, 470, 920, 65, 509, 525, 879, 378, + 452, 72, 222, 720, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (808, 318, 478, 42, 706, 500, 264, 14, + 397, 261, 862, 33, 864, 62, 462, 305, + 509, 231, 316, 800, 465, 452, 738, 126, + 239, 9, 845, 241, 656, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (563, 235, 604, 915, 635, 324, 392, 364, + 683, 541, 89, 655, 211, 194, 136, 453, + 104, 12, 390, 487, 484, 794, 549, 471, + 26, 910, 498, 383, 138, 926, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (757, 764, 673, 108, 706, 886, 76, 234, + 695, 196, 66, 270, 8, 252, 612, 825, + 660, 679, 860, 898, 204, 861, 371, 142, + 358, 380, 528, 379, 120, 757, 347, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (410, 63, 330, 685, 390, 231, 133, 803, + 320, 571, 800, 593, 147, 263, 494, 273, + 517, 193, 284, 687, 742, 677, 742, 536, + 321, 640, 586, 176, 525, 922, 575, 361, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (575, 871, 311, 454, 504, 870, 199, 768, + 634, 362, 548, 855, 529, 384, 830, 923, + 222, 85, 841, 59, 518, 590, 358, 110, + 695, 864, 699, 581, 642, 175, 836, 855, + 709, 274, 686, 244, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 5, 10, 156, 729, 684, 324, 60, 264, + 99, 261, 89, 460, 742, 208, 699, 670, + 512, 404, 726, 389, 492, 287, 894, 571, + 41, 203, 353, 256, 243, 784, 385, 555, + 595, 734, 714, 565, 205, 706, 316, 115, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (285, 82, 730, 339, 436, 572, 271, 103, + 758, 231, 560, 31, 213, 272, 267, 569, + 773, 3, 21, 446, 706, 413, 97, 376, + 60, 714, 436, 417, 405, 632, 25, 109, + 876, 470, 915, 157, 840, 764, 64, 678, + 848, 659, 36, 476, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (669, 912, 896, 252, 338, 162, 414, 632, + 626, 252, 869, 185, 444, 82, 920, 783, + 565, 875, 126, 877, 524, 603, 189, 136, + 373, 540, 649, 271, 836, 540, 199, 323, + 888, 486, 92, 849, 162, 701, 178, 926, + 498, 575, 765, 422, 450, 302, 354, 710, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (187, 57, 15, 317, 835, 593, 8, 158, + 95, 145, 37, 659, 576, 386, 884, 913, + 495, 869, 908, 296, 437, 215, 33, 883, + 877, 477, 712, 578, 349, 13, 174, 839, + 914, 107, 260, 40, 532, 210, 395, 905, + 163, 785, 693, 627, 393, 687, 112, 481, + 717, 297, 37, 483, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (163, 726, 626, 653, 414, 537, 467, 579, + 729, 396, 142, 598, 860, 774, 518, 461, + 136, 687, 827, 614, 841, 468, 207, 481, + 649, 910, 497, 686, 186, 235, 845, 863, + 821, 711, 663, 534, 393, 756, 467, 224, + 442, 520, 210, 732, 864, 729, 433, 735, + 70, 184, 278, 97, 492, 17, 2, 338, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 77, 611, 467, 704, 555, 579, 802, 773, + 303, 518, 560, 196, 314, 102, 5, 845, + 248, 125, 836, 923, 88, 630, 886, 619, + 37, 141, 409, 229, 77, 658, 450, 449, + 93, 651, 276, 501, 166, 75, 630, 701, + 388, 72, 830, 166, 187, 131, 711, 577, + 834, 147, 361, 517, 76, 581, 45, 495, + 366, 278, 781, 61, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0), + (543, 264, 623, 843, 381, 4, 629, 840, + 771, 280, 97, 404, 83, 717, 733, 648, + 502, 488, 201, 651, 158, 605, 352, 517, + 535, 225, 594, 460, 31, 519, 35, 440, + 184, 283, 762, 672, 400, 511, 376, 543, + 822, 858, 609, 430, 172, 462, 476, 723, + 612, 381, 877, 733, 505, 107, 287, 610, + 106, 453, 771, 862, 93, 6, 422, 539, 0)); + + StMods128 : array [0..127] of Integer = + (521, 310, 864, 547, 858, 580, 296, 379, + 53, 779, 897, 444, 400, 925, 749, 415, + 822, 93, 217, 208, 928, 244, 583, 620, + 246, 148, 447, 631, 292, 908, 490, 704, + 516, 258, 457, 907, 594, 723, 674, 292, + 272, 96, 684, 432, 686, 606, 860, 569, + 193, 219, 129, 186, 236, 287, 192, 775, + 278, 173, 40, 379, 712, 463, 646, 776, + 171, 491, 297, 763, 156, 732, 95, 270, + 447, 90, 507, 48, 228, 821, 808, 898, + 784, 663, 627, 378, 382, 262, 380, 602, + 754, 336, 89, 614, 87, 432, 670, 616, + 157, 374, 242, 726, 600, 269, 375, 898, + 845, 454, 354, 130, 814, 587, 804, 34, + 211, 330, 539, 297, 827, 865, 37, 517, + 834, 315, 550, 86, 801, 4, 108, 539); + + StMods256 : array [0..255] of Integer = + (524, 894, 75, 766, 882, 857, 74, 204, + 82, 586, 708, 250, 905, 786, 138, 720, + 858, 194, 311, 913, 275, 190, 375, 850, + 438, 733, 194, 280, 201, 280, 828, 757, + 710, 814, 919, 89, 68, 569, 11, 204, + 796, 605, 540, 913, 801, 700, 799, 137, + 439, 418, 592, 668, 353, 859, 370, 694, + 325, 240, 216, 257, 284, 549, 209, 884, + 315, 70, 329, 793, 490, 274, 877, 162, + 749, 812, 684, 461, 334, 376, 849, 521, + 307, 291, 803, 712, 19, 358, 399, 908, + 103, 511, 51, 8, 517, 225, 289, 470, + 637, 731, 66, 255, 917, 269, 463, 830, + 730, 433, 848, 585, 136, 538, 906, 90, + 2, 290, 743, 199, 655, 903, 329, 49, + 802, 580, 355, 588, 188, 462, 10, 134, + 628, 320, 479, 130, 739, 71, 263, 318, + 374, 601, 192, 605, 142, 673, 687, 234, + 722, 384, 177, 752, 607, 640, 455, 193, + 689, 707, 805, 641, 48, 60, 732, 621, + 895, 544, 261, 852, 655, 309, 697, 755, + 756, 60, 231, 773, 434, 421, 726, 528, + 503, 118, 49, 795, 32, 144, 500, 238, + 836, 394, 280, 566, 319, 9, 647, 550, + 73, 914, 342, 126, 32, 681, 331, 792, + 620, 60, 609, 441, 180, 791, 893, 754, + 605, 383, 228, 749, 760, 213, 54, 297, + 134, 54, 834, 299, 922, 191, 910, 532, + 609, 829, 189, 20, 167, 29, 872, 449, + 83, 402, 41, 656, 505, 579, 481, 173, + 404, 251, 688, 95, 497, 555, 642, 543, + 307, 159, 924, 558, 648, 55, 497, 10); + + StMods512 : array [0..511] of Integer = + (352, 77, 373, 504, 35, 599, 428, 207, + 409, 574, 118, 498, 285, 380, 350, 492, + 197, 265, 920, 155, 914, 299, 229, 643, + 294, 871, 306, 88, 87, 193, 352, 781, + 846, 75, 327, 520, 435, 543, 203, 666, + 249, 346, 781, 621, 640, 268, 794, 534, + 539, 781, 408, 390, 644, 102, 476, 499, + 290, 632, 545, 37, 858, 916, 552, 41, + 542, 289, 122, 272, 383, 800, 485, 98, + 752, 472, 761, 107, 784, 860, 658, 741, + 290, 204, 681, 407, 855, 85, 99, 62, + 482, 180, 20, 297, 451, 593, 913, 142, + 808, 684, 287, 536, 561, 76, 653, 899, + 729, 567, 744, 390, 513, 192, 516, 258, + 240, 518, 794, 395, 768, 848, 51, 610, + 384, 168, 190, 826, 328, 596, 786, 303, + 570, 381, 415, 641, 156, 237, 151, 429, + 531, 207, 676, 710, 89, 168, 304, 402, + 40, 708, 575, 162, 864, 229, 65, 861, + 841, 512, 164, 477, 221, 92, 358, 785, + 288, 357, 850, 836, 827, 736, 707, 94, + 8, 494, 114, 521, 2, 499, 851, 543, + 152, 729, 771, 95, 248, 361, 578, 323, + 856, 797, 289, 51, 684, 466, 533, 820, + 669, 45, 902, 452, 167, 342, 244, 173, + 35, 463, 651, 51, 699, 591, 452, 578, + 37, 124, 298, 332, 552, 43, 427, 119, + 662, 777, 475, 850, 764, 364, 578, 911, + 283, 711, 472, 420, 245, 288, 594, 394, + 511, 327, 589, 777, 699, 688, 43, 408, + 842, 383, 721, 521, 560, 644, 714, 559, + 62, 145, 873, 663, 713, 159, 672, 729, + 624, 59, 193, 417, 158, 209, 563, 564, + 343, 693, 109, 608, 563, 365, 181, 772, + 677, 310, 248, 353, 708, 410, 579, 870, + 617, 841, 632, 860, 289, 536, 35, 777, + 618, 586, 424, 833, 77, 597, 346, 269, + 757, 632, 695, 751, 331, 247, 184, 45, + 787, 680, 18, 66, 407, 369, 54, 492, + 228, 613, 830, 922, 437, 519, 644, 905, + 789, 420, 305, 441, 207, 300, 892, 827, + 141, 537, 381, 662, 513, 56, 252, 341, + 242, 797, 838, 837, 720, 224, 307, 631, + 61, 87, 560, 310, 756, 665, 397, 808, + 851, 309, 473, 795, 378, 31, 647, 915, + 459, 806, 590, 731, 425, 216, 548, 249, + 321, 881, 699, 535, 673, 782, 210, 815, + 905, 303, 843, 922, 281, 73, 469, 791, + 660, 162, 498, 308, 155, 422, 907, 817, + 187, 62, 16, 425, 535, 336, 286, 437, + 375, 273, 610, 296, 183, 923, 116, 667, + 751, 353, 62, 366, 691, 379, 687, 842, + 37, 357, 720, 742, 330, 5, 39, 923, + 311, 424, 242, 749, 321, 54, 669, 316, + 342, 299, 534, 105, 667, 488, 640, 672, + 576, 540, 316, 486, 721, 610, 46, 656, + 447, 171, 616, 464, 190, 531, 297, 321, + 762, 752, 533, 175, 134, 14, 381, 433, + 717, 45, 111, 20, 596, 284, 736, 138, + 646, 411, 877, 669, 141, 919, 45, 780, + 407, 164, 332, 899, 165, 726, 600, 325, + 498, 655, 357, 752, 768, 223, 849, 647, + 63, 310, 863, 251, 366, 304, 282, 738, + 675, 410, 389, 244, 31, 121, 303, 263); + +var + BaseReg : array [0..800] of DWord; + CoeffReg : array [0..800] of DWord; + i : Integer; + j : Integer; + TInt : Integer; + Temp : DWord; + Wrap : DWord; + +begin + if ECClen < 128 then + for i := 0 to ECCLen - 1 do + CoeffReg[i] := StMods[ECClen][i] + else begin + if ECClen = 128 then + for i := 0 to ECCLen - 1 do + CoeffReg[i] := StMods128[i] + else if ECClen = 256 then + for i := 0 to ECCLen - 1 do + CoeffReg[i] := StMods256[i] + else if ECClen = 512 then + for i := 0 to ECCLen - 1 do + CoeffReg[i] := StMods512[i]; + end; + + for i := 0 to ECCLen - 1 do + BaseReg[i] := 0; + + for i := NumCodewords to NumCodewords + ECCLen - 1 do + FCodewords[i] := 0; + + for i := 0 to NumCodewords - 1 do begin + wrap := (BaseReg[ECClen - 1] + FCodewords[i]) mod 929; + for j := ECCLen - 1 downto 1 do begin + temp := (CoeffReg[ECClen - 1 - j] * wrap) mod 929; + temp := (929 - temp) mod 929; + BaseReg[j] := (BaseReg[j - 1] + temp) mod 929; + end; + temp := (CoeffReg[ECClen - 1] * wrap) mod 929; + temp := (929 - temp) mod 929; + BaseReg[0]:= temp; + end; + + for j := 0 to ECCLen - 1 do + BaseReg[j] := (929 - BaseReg[j]) mod 929; + + for j := 0 to ECCLen - 1 do begin + tint := BaseReg[ECClen - 1 - j]; + FCodewords [NumCodewords + j] := tint; + end; +end; + +procedure TStPDF417Barcode.CalculateSize (var XSize : Integer; + var YSize : Integer); +var + i : Integer; + NumErrorCodewords : Integer; + ErrorLevel : Integer; + j : Integer; + +begin + { Set the error correction level automatically if needed } + ErrorLevel := GetRealErrorLevel; + + NumErrorCodewords := Trunc (Power (2, ErrorLevel + 1)); + + XSize := NumColumns; + YSize := NumRows; + + FTotalCodewords := XSize * YSize; + + { Adjust the size if necessary } + if (NumRows <= 0) or (NumColumns <= 0) then begin + if NumRows > 0 then begin + i := 1; + while i <= 30 do begin + if i * NumRows - NumErrorCodewords > FNumCodewords then + Break; + Inc (i); + end; + FTotalCodewords := YSize * 30; + XSize := i; + end else if NumColumns > 0 then begin + i := 3; + while i <= 90 do begin + if i * NumColumns - NumErrorCodewords > FNumCodewords then + Break; + Inc (i); + end; + YSize := i; + FTotalCodewords := XSize * 90; + end else begin + i := 1; + j := 3; + while (i * j - NumErrorCodewords < FNumCodewords) do begin + if j < 90 then + Inc (j); + if (i < 30) and (i * j - NumErrorCodewords < FNumCodewords) then + Inc (i); + if (j >= 90) and (i >= 30) then + Break; + end; + XSize := i; + YSize := J; + FTotalCodewords := 900; + end; + end; +end; + +function TStPDF417Barcode.CodewordToBitmask (RowNumber : Integer; + Codeword : Integer) : DWord; +begin + if (Codeword < 0) or (CodeWord > 929) then + raise E2DBarcodeError.Create (StEInvalidCodeword); + Result := StPDF417Codewords[RowNumber mod 3][Codeword]; +end; + +procedure TStPDF417Barcode.ConvertBytesToBase900 (const S : array of Byte; + var A : array of Integer); +var + i : Integer; + D : array [0..5] of Byte; + Dividend : Integer; + Digits : array [0..4] of Integer; + SP : Integer; + +begin +// Assert(length(S) = 6, +// 'ConvertBytesToBase900: there should be 6 bytes in the input byte array'); +// Assert(length(A) = 5, +// 'ConvertBytesToBase900: there should be 5 elements in the output digit array'); + + {copy the array of bytes} + for i := 0 to 5 do + D[i] := S[i]; + + {loop until the entire base 256 value has been converted to an array + of base 900 digits (6 base 256 digits will convert to 5 base 900 + digits)} + SP := 0; + while (SP < 5) do begin + Dividend := 0; + for i := 0 to 5 do begin + {notes: at the start of the loop, Dividend will always be in the + range 0..899--it starts out as zero and the final + statement in the loop forces it into that range + the first calculation sets Dividend to 0..230399 + the second calc sets D[i] to 0..255 (with no possibility + of overflow) + the third calc sets Dividend to 0..899 again} + Dividend := (Dividend shl 8) + D[i]; + D[i] := Dividend div 900; + Dividend := Dividend mod 900; + end; + + Digits[SP] := Dividend; + inc(SP); + end; + + {pop the base 900 digits and enter them into the array of integers} + i := 0; + while (SP > 0) do begin + dec(SP); + A[i] := Digits[SP]; + inc(i); + end; +end; + +procedure TStPDF417Barcode.ConvertToBase900 (const S : string; + var A : array of Integer; + var LenA : Integer); +var + D : string; + i : Integer; + LenD : Integer; + Dividend : Integer; + Rem : Integer; + Done : Boolean; + FirstDigit : Integer; + Digits : array [0..14] of Integer; + // 15 base 900 digits = 45 base 10 digits + SP : Integer; + +begin + {Assert: S must be non-empty + it must contain just the ASCII characters '0' to '9' (so no + leading/trailing spaces either) + it must have a maximum length of 45} + Assert(IsNumericString(S), 'ConvertToBase900: S should be a numeric string'); + + {grab the string and calculate its length} + D := S; + LenD := length(D); + + {convert the string from ASCII characters into binary digits and in + the process calculate the first non-zero digit} + FirstDigit := 0; + for i := LenD downto 1 do begin + D[i] := char(ord(D[i]) - ord('0')); + if (D[i] <> #0) then + FirstDigit := i; + end; + + {if the input string comprises just zero digits, return} + if (FirstDigit = 0) then begin + LenA := 0; + Exit; + end; + + {prepare the stack of base 900 digits} + SP := 0; + + {loop until the entire base 10 string has been converted to an array + of base 900 digits} + Done := false; + while not Done do begin + + {if we can switch to using standard integer arithmetic, do so} + if ((LenD - FirstDigit) <= 8) then begin + + {convert the remaining digits to a binary integer} + Dividend := 0; + for i := FirstDigit to LenD do + Dividend := (Dividend * 10) + ord(D[i]); + + {calculate the remaining base 900 digits using the standard + radix conversion algorithm; push onto the digit stack} + while (Dividend <> 0) do begin + Digits[SP] := Dividend mod 900; + inc(SP); + Dividend := Dividend div 900; + end; + + {we've finished} + Done := true; + end + + {otherwise operate directly on the base 10 string} + else begin + + {calculate the remainder base 100} + Rem := ord(D[LenD]); + dec(LenD); + Rem := Rem + (ord(D[LenD]) * 10); + dec(LenD); + + {calculate the quotient and remainder of the remaining digits, + dividing by 9} + Dividend := 0; + for i := FirstDigit to LenD do begin + Dividend := (Dividend * 10) + ord(D[i]); + D[i] := char(Dividend div 9); + Dividend := Dividend mod 9; + end; + + {push the base 900 digit onto the stack: it's the remainder base + 9 multiplied by 100, plus the remainder base 100} + Digits[SP] := (Dividend * 100) + Rem; + inc(SP); + + {if the first digit is now zero, advance the index to the first + non-zero digit} + if (D[FirstDigit] = '0') then + inc(FirstDigit); + end; + end; + + {pop the base 900 digits and enter them into the array of integers} + i := 0; + while (SP > 0) do begin + dec(SP); + A[i] := Digits[SP]; + inc(i); + end; + LenA := i; +end; + +procedure TStPDF417Barcode.DrawBarcode; +var + XSize : Integer; + YSize : Integer; + i : Integer; + j : Integer; + WorkBarHeight : Integer; + CodewordPos : Integer; + ErrorLevel : Integer; + NumErrorCodewords : Integer; + +const + SymbolPadding = 900; + +begin + { Set the error correction level automatically if needed } + ErrorLevel := GetRealErrorLevel; + + NumErrorCodewords := Trunc (Power (2, ErrorLevel + 1)); + + CalculateSize (XSize, YSize); + + { The first codewords is always the length } + if FNumCodewords + + (XSize * YSize - FNumCodewords - NumErrorCodewords) < 0 then + raise E2DBarcodeError.Create (StECodeTooLarge); + FCodewords[0] := FNumCodewords + + (XSize * YSize - FNumCodewords - NumErrorCodewords); + + CodewordPos := 1; { The first codeword is always the length } + + WorkBarHeight := (BarCodeRect.Bottom - BarCodeRect.Top) div YSize; + + for i := 0 to YSize - 1 do begin + if FHighlight then + FBitmap.Canvas.Brush.Color := $ffbbff; + DrawStartPattern (i, WorkBarHeight); + if FHighlight then + FBitmap.Canvas.Brush.Color := $ffffbb; + DrawLeftRowIndicator (i, WorkBarHeight, YSize, XSize); + for j := 0 to XSize - 1 do begin + if (i = 0) and (j = 0) then begin + if FHighlight then + FBitmap.Canvas.Brush.Color := $bbffff; + { Length } + DrawCodeWordBitmask (i, j + 2, WorkBarHeight, + CodeWordToBitmask (i, FNumCodewords + + (XSize * YSize - FNumCodewords - NumErrorCodewords))) + end else if CodewordPos < FNumCodewords then begin + if FHighlight then + FBitmap.Canvas.Brush.Color := $bbbbff; + { Data } + DrawCodeWordBitmask (i, j + 2, WorkBarHeight, + CodewordToBitmask (i, FCodewords[CodewordPos])); + Inc (CodewordPos); + end else if CodewordPos >= XSize * YSize - NumErrorCodeWords then begin + if FHighlight then + FBitmap.Canvas.Brush.Color := $ffbbbb; + { Error Correction Codes } + DrawCodeWordBitmask (i, j + 2, WorkBarHeight, + CodewordToBitmask (i, FCodewords[CodewordPos])); + Inc (CodewordPos); + end else begin + if FHighlight then + FBitmap.Canvas.Brush.Color := $bbffbb; + { Padding } + DrawCodewordBitmask (i, j + 2, WorkBarHeight, + CodewordToBitmask (i, SymbolPadding)); + Inc (CodewordPos); + end; + end; + if FHighlight then + FBitmap.Canvas.Brush.Color := $bbddff; + if Truncated then + DrawStopPattern (i, XSize + 2, WorkBarHeight) + else begin + DrawRightRowIndicator (i, XSize + 2, WorkBarHeight, YSize, XSize); + if FHighlight then + FBitmap.Canvas.Brush.Color := $ddaaff; + DrawStopPattern (i, XSize + 3, WorkBarHeight); + end; + end; +end; + +procedure TStPDF417Barcode.DrawCodeword (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer; + Pattern : string); + + function GetColumnPosition (ColNumber : Integer) : Integer; + begin + Result := ColNumber * StPDF417CellWidth * BarWidth; + end; + +var + i : Integer; + CurPos : Integer; + NewPos : Integer; + DrawBlock : Boolean; + +begin + if FHighlight then begin + FBitmap.Canvas.FillRect ( + Rect (BarCodeRect.Left + (GetColumnPosition (ColNumber)), + BarCodeRect.Top + RowNumber * WorkBarHeight, + BarCodeRect.Left + 17 * BarWidth + GetColumnPosition (ColNumber), + BarCodeRect.Top + (RowNumber + 1) * WorkBarHeight)); + FBitmap.Canvas.Brush.Color := Color; + end; + + CurPos := 0; + DrawBlock := True; + for i := 1 to Length (Pattern) do begin + NewPos := StrToInt (Copy (Pattern, i, 1)) * BarWidth; + if DrawBlock then + FBitmap.Canvas.Rectangle ( + BarCodeRect.Left + CurPos + GetColumnPosition (ColNumber), + BarCodeRect.Top + RowNumber * WorkBarHeight, + BarCodeRect.Left + CurPos + NewPos + GetColumnPosition (ColNumber), + BarCodeRect.Top + (RowNumber + 1) * WorkBarHeight); + CurPos := CurPos + NewPos; + DrawBlock := not DrawBlock; + end; +end; + +procedure TStPDF417Barcode.DrawCodewordBitmask (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer; + Bitmask : DWord); + + function GetColumnPosition (ColNumber : Integer) : Integer; + begin + Result := ColNumber * StPDF417CellWidth * BarWidth; + end; + +var + i : Integer; + +begin + if FHighlight then begin + FBitmap.Canvas.FillRect ( + Rect (BarCodeRect.Left + (GetColumnPosition (ColNumber)), + BarCodeRect.Top + RowNumber * WorkBarHeight, + BarCodeRect.Left + 17 * BarWidth + GetColumnPosition (ColNumber), + BarCodeRect.Top + (RowNumber + 1) * WorkBarHeight)); + FBitmap.Canvas.Brush.Color := Color; + end; + + for i := 16 downto 0 do + if ((BitMask shr i) and $00001) <> 0 then + FBitmap.Canvas.Rectangle ( + BarCodeRect.Left + (16 - i) * BarWidth + + GetColumnPosition (ColNumber), + BarCodeRect.Top + RowNumber * WorkBarHeight, + BarCodeRect.Left + (17 - i) * BarWidth + + GetColumnPosition (ColNumber), + BarCodeRect.Top + (RowNumber + 1) * WorkBarHeight); +end; + +procedure TStPDF417Barcode.DrawLeftRowIndicator (RowNumber : Integer; + WorkBarHeight : Integer; + NumRows : Integer; + NumCols : Integer); +var + CodeWord : Integer; + ErrorLevel : Integer; + +begin + ErrorLevel := GetRealErrorLevel; + CodeWord := 0; + if RowNumber mod 3 = 0 then + CodeWord := ((RowNumber div 3) * 30) + ((NumRows - 1) div 3) + else if RowNumber mod 3 = 1 then + CodeWord := ((RowNumber div 3) * 30) + ((NumRows - 1) mod 3) + + (3 * ErrorLevel) + else if RowNumber mod 3 = 2 then + CodeWord := (( RowNumber div 3) * 30) + (NumCols - 1); + DrawCodeWordBitmask (RowNumber, 1, WorkBarHeight, + CodewordToBitmask (RowNumber, Codeword)); +end; + +procedure TStPDF417Barcode.DrawRightRowIndicator (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer; + NumRows : Integer; + NumCols : Integer); +var + Codeword : Integer; + ErrorLevel : Integer; + +begin + ErrorLevel := GetRealErrorLevel; + CodeWord := 0; + if RowNumber mod 3 = 0 then + Codeword := ((RowNumber div 3) * 30) + (NumCols - 1) + else if RowNumber mod 3 = 1 then + Codeword := ((RowNumber div 3) * 30) + ((NumRows - 1) div 3) + else if RowNumber mod 3 = 2 then + Codeword := ((RowNumber div 3) * 30) + ((NumRows - 1) mod 3) + + (3 * ErrorLevel); + DrawCodeWordBitmask (RowNumber, ColNumber, WorkBarHeight, + CodewordToBitmask (RowNumber, Codeword)); +end; + +procedure TStPDF417Barcode.DrawStartPattern (RowNumber : Integer; + WorkBarHeight : Integer); +begin + DrawCodeword (RowNumber, 0, WorkBarHeight, '81111113'); +end; + +procedure TStPDF417Barcode.DrawStopPattern (RowNumber : Integer; + ColNumber : Integer; + WorkBarHeight : Integer); +begin + if Truncated then + DrawCodeWord (RowNumber, ColNumber, WorkBarHeight, '1') + else + DrawCodeWord (RowNumber, ColNumber, WorkBarHeight, '711311121'); +end; + +procedure TStPDF417Barcode.EncodeBinary (var Position : Integer; + CodeLen : Integer); + + function CountBytes (Position : Integer; CodeLen : Integer) : Integer; + var + Done : Boolean; + Dummy : Integer; + + begin + Result := 0; + Done := False; + while not done do begin + if (Result < CodeLen) and + (not GoodForNumericCompaction (Position + Result, CodeLen, Dummy)) and + (not GoodForTextCompaction (Position + Result, CodeLen, Dummy)) then + Inc (Result) + else + Done := True; + end; + end; + +var + MultipleOfSix : Boolean; + BinaryDataSize : Integer; + i : Integer; + j : Integer; + A : array [0..6] of Integer; + +const + Even6Bytes = 924; + Odd6Bytes = 901; + +begin + BinaryDataSize := CountBytes (Position, CodeLen); + if BinaryDataSize mod 6 = 0 then + MultipleOfSix := True + else + MultipleOfSix := False; + if MultipleOfSix then + AddCodeword (Even6Bytes) + else + AddCodeword (Odd6Bytes); + + i := 0; + while i < BinaryDataSize do + if BinaryDataSize - i < 6 then begin + AddCodeword (Word (Code[Position + i])); + Inc (i); + end else begin + ConvertBytesToBase900 ([Byte (Code[Position + i]), + Byte (Code[Position + i + 1]), + Byte (Code[Position + i + 2]), + Byte (Code[Position + i + 3]), + Byte (Code[Position + i + 4]), + Byte (Code[Position + i + 5])], A); + for j := 1 to 5 do + AddCodeword (A[j - 1]); {!!.dg} + Inc (i, 6); + end; + Inc (Position, BinaryDataSize); {!!.dg} +end; + +procedure TStPDF417Barcode.EncodeNumeric (var Position : Integer; + CodeLen : Integer); + + function CollectDigits (var Position : Integer; + CodeLen : Integer) : string; + var + StartPos : Integer; + + const + MaxDigitChunk = 44; + + begin + Result := ''; + StartPos := Position; + while (Position <= CodeLen) and (Position - StartPos < MaxDigitChunk) and + (Code[Position] >= '0') and (Code[Position] <= '9') do begin + Inc (Position); + end; + if Position - StartPos > 0 then + Result := '1' + Copy (Code, StartPos, Position - StartPos); + end; + +var + NumericString : string; + A : array [0..44] of Integer; + LenA : Integer; + i : Integer; + +const + NumericLatch = 902; + +begin + AddCodeword (NumericLatch); + repeat + NumericString := CollectDigits (Position, CodeLen); + if NumericString <> '' then begin + ConvertToBase900 (NumericString, A, LenA); + for i := 0 to LenA do + AddCodeword (A[i]); + end; + until NumericString = ''; +end; + +procedure TStPDF417Barcode.EncodeText (var Position : Integer; + CodeLen : Integer); + + function SelectBestTextMode ( + CurChar : TStPDF417TextCompactionData) : TStPDF417TextCompactionMode; + begin + if cmAlpha in CurChar.Mode then + Result := cmAlpha + else if cmLower in CurChar.Mode then + Result := cmLower + else if cmMixed in CurChar.Mode then + Result := cmMixed + else if cmPunctuation in CurChar.Mode then + Result := cmPunctuation + else + Result := cmNone; + end; + + procedure AddTextCharacter (Value : Word); + begin + if FNewTextCodeword then + FCodewords[FNumCodewords] := 30 * Value + else begin + FCodewords[FNumCodewords] := FCodewords[FNumCodewords] + Value; + Inc (FNumCodewords); + end; + FNewTextCodeword := not FNewTextCodeword; + end; + + function ChangeTextSubmode (CurrentMode : TStPDF417TextCompactionMode; + NewMode : TStPDF417TextCompactionMode; + UseShift : Boolean) : TStPDF417TextCompactionMode; + const + LatchAlphaToLower = 27; + LatchAlphaToMixed = 28; + ShiftAlphaToPunctuation = 29; + ShiftLowerToAlpha = 27; + LatchLowerToMixed = 28; + ShiftLowertoPunctuation = 29; + LatchMixedToPunctuation = 25; + LatchMixedToLower = 27; + LatchMixedToAlpha = 28; + ShiftMixedToPunctuation = 29; + LatchPunctuationToAlpha = 29; + + begin + if UseShift then + Result := CurrentMode + else + Result := NewMode; + + case CurrentMode of + cmAlpha : + case NewMode of + cmLower : + begin + { Alpha to Lower. No shift } + AddTextCharacter (LatchAlphaToLower); + if UseShift then + Result := NewMode; + end; + cmMixed : + begin + { Alpha to Numeric. No shift } + AddTextCharacter (LatchAlphaToMixed); + if UseShift then + Result := NewMode; + end; + cmPunctuation : + { Alpha to Punctuation } + if UseShift then + AddTextCharacter (ShiftAlphaToPunctuation) + else begin + AddTextCharacter (LatchAlphaToMixed); + AddTextCharacter (LatchMixedToPunctuation); + end; + end; + + cmLower : + case NewMode of + cmAlpha : + { Lower to Alpha } + if UseShift then + AddTextCharacter (ShiftLowerToAlpha) + else begin + AddTextCharacter (LatchLowerToMixed); + AddTextCharacter (LatchMixedToAlpha); + end; + cmMixed : + begin + { Lower to Mixed. No shift } + AddTextCharacter (LatchLowerToMixed); + if UseShift then + Result := NewMode; + end; + cmPunctuation : + { Lower to Punctuation } + if UseShift then + AddTextCharacter (ShiftLowerToPunctuation) + else begin + AddTextCharacter (LatchLowerToMixed); + AddTextCharacter (LatchMixedToPunctuation); + end; + end; + + cmMixed : + case NewMode of + cmAlpha : + begin + { Mixed to Alpha. No shift } + AddTextCharacter (LatchMixedToAlpha); + if UseShift then + Result := NewMode; + end; + cmLower : + begin + { Mixed to Lower. No shift } + AddTextCharacter (LatchMixedToLower); + if UseShift then + Result := NewMode; + end; + cmPunctuation : + { Mixed to Punctuation } + if UseShift then + AddTextCharacter (ShiftMixedToPunctuation) + else + AddTextCharacter (LatchMixedToPunctuation); + end; + cmPunctuation : + case NewMode of + cmAlpha : + begin + { Punctuation to Alpha. No shift } + AddTextCharacter (LatchPunctuationToAlpha); + if UseShift then + Result := NewMode; + end; + cmLower : + begin + { Punctuation to Lower. No shift } + AddTextCharacter (LatchPunctuationToAlpha); + AddTextCharacter (LatchAlphaToLower); + if UseShift then + Result := NewMode; + end; + cmMixed : + begin + { Punctuation to Mixed. No shift } + AddTextCharacter (LatchPunctuationToAlpha); + AddTextCharacter (LatchAlphaToMixed); + if UseShift then + Result := NewMode; + end; + end; + end; + end; + +var + CurrentTextSubmode : TStPDF417TextCompactionMode; + CurChar : TStPDF417TextCompactionData; + UseShift : Boolean; + Done : Boolean; + Dummy : Integer; + NewChar : Integer; + Codeword : Boolean; + +const + EndingPadChar = 29; + +begin + { Initialize and get the first character } + FNewTextCodeword := True; + CurrentTextSubmode := cmAlpha; + Done := False; + + { get characters until it is necessary to step out of text mode } + while (Position <= CodeLen) and (CurChar.Value >= 0) and + (not Done) do begin + if (Position <= CodeLen) then begin + GetNextCharacter (NewChar, Codeword, Position, CodeLen); + CurChar := TStPDF417TextCompaction[NewChar]; + end; + + if Codeword then begin + { If the text contains an odd number of letters, follow it with a + trailing 29 } + if not FNewTextCodeword then + AddTextCharacter (EndingPadChar); + FNewTextCodeword := True; + { Add the codeword } + AddCodeword (NewChar) + end else begin + { Check if the text submode for the current character is different than + the current text submode } + if not (CurrentTextSubmode in CurChar.Mode) then begin + { if the text submode is different, see if it remains different. If + it does, use a latch, otherwise just shift } + if Position < CodeLen then begin + if not (CurrentTextSubmode in + TStPDF417TextCompaction[Integer (Code[Position + 1])].Mode) then + UseShift := False + else + UseShift := True; + end else + UseShift := True; + + { Add the shift or latch to the text codewords } + CurrentTextSubmode := ChangeTextSubmode (CurrentTextSubmode, + SelectBestTextMode (CurChar), + UseShift); + end; + + { Add the character to the codeword array } + AddTextCharacter (CurChar.Value); + end; + { If this is a digit and it looks like a good time to switch to + numeric mode, do so } + if GoodForNumericCompaction (Position, CodeLen, Dummy) then + Done := True; + end; + + { If the text contains an odd number of letters, follow it with a + trailing 29 } + if not FNewTextCodeword then + AddTextCharacter (EndingPadChar); +end; + +procedure TStPDF417Barcode.GenerateCodewords; +var + ErrorLevel : Integer; + NumErrorCodewords : Integer; + XSize : Integer; + YSize : Integer; + +begin + TextToCodewords; + + ErrorLevel := GetRealErrorLevel; + + NumErrorCodewords := Trunc (Power (2, ErrorLevel + 1)); + + CalculateSize (XSize, YSize); + + FUsedCodewords := FNumCodewords; + FUsedECCCodewords := NumErrorCodewords; + FFreeCodewords := FTotalCodewords - FUsedCodewords; + + { The first codewords is always the length } + if FNumCodewords + + (XSize * YSize - FNumCodewords - NumErrorCodewords) < 0 then + raise E2DBarcodeError.Create (StECodeTooLarge); + FCodewords[0] := FNumCodewords + + (XSize * YSize - FNumCodewords - NumErrorCodewords); + + if NumErrorCodeWords + FNumCodeWords <= XSize * YSize then + CalculateECC (XSize * YSize - NumErrorCodeWords, NumErrorCodewords) + else + raise E2DBarcodeError.Create (StECodeTooLarge); +end; + +procedure TStPDF417Barcode.GetNextCharacter (var NewChar : Integer; + var Codeword : Boolean; + var Position : Integer; + CodeLen : Integer); +var + WorkNum : Integer; + +begin + NewChar := 0; + Codeword := False; + + if Position <= CodeLen then begin + if (FCode[Position] = '\') and + (Position < CodeLen) then begin + case FCode[Position + 1] of + '0'..'9' : begin + try + NewChar := StrToInt (Copy (FCode, Position + 1, 3)); + Inc (Position, 4); + except + NewChar := 0; + Inc (Position, 4); + end; + end; + 'C', 'c' : begin + try + Codeword := True; + NewChar := StrToInt (Copy (FCode, Position + 2, 3)); + Inc (Position, 5); + except + NewChar := 0; + Inc (Position, 5); + end; + end; + 'G', 'g' : begin + WorkNum := StrToInt (Copy (FCode, Position + 1, 6)); + Inc (Position, 8); + if (WorkNum >= 0) and (WorkNum <= 899) then begin + AddCodeword (927); + Codeword := True; + NewChar := WorkNum; + end else if (WorkNum >= 900) and (WorkNum < 810900) then begin + AddCodeword (926); + AddCodeword ((WorkNum div 900) - 1); + Codeword := True; + NewChar := WorkNum mod 900; + end else if (WorkNum >= 810900) and (WorkNum < 811800) then begin + AddCodeword (925); + Codeword := True; + NewChar := WorkNum; + end else + raise E2DBarcodeError.Create (StEGLIOutOfRange); + end; + 'X', 'x' : begin + try + NewChar := StrToInt ('$' + Copy (FCode, Position + 2, 2)); + Inc (Position, 4); + except + NewChar := 0; + Inc (Position, 4); + end; + end; + '\' : begin + NewChar := Byte (FCode[Position]); + Inc (Position, 2); + end; + else begin + NewChar := Byte (FCode[Position]); + Inc (Position); + end; + end; + end else begin + NewChar := Byte (FCode[Position]); + Inc (Position); + end; + end; +end; + +function TStPDF417Barcode.GetPDF417ECCLevel : TStPDF417ECCLevels; +begin + case FECCLevel of + 0 : Result := ecLevel0; + 1 : Result := ecLevel1; + 2 : Result := ecLevel2; + 3 : Result := ecLevel3; + 4 : Result := ecLevel4; + 5 : Result := ecLevel5; + 6 : Result := ecLevel6; + 7 : Result := ecLevel7; + 8 : Result := ecLevel8; + else + Result := ecAuto; + end; +end; + +function TStPDF417Barcode.GetRealErrorLevel : Integer; +begin + if (FECCLevel < 0) then begin + if FNumCodeWords < 41 then + Result := 2 + else if FNumCodeWords < 161 then + Result := 3 + else if FNumCodeWords < 321 then + Result := 4 + else + Result := 5; + end else + Result := FECCLevel +end; + +function TStPDF417Barcode.GoodForNumericCompaction ( + Position : Integer; + CodeLen : Integer; + var Count : Integer) : Boolean; +const + BytesNeeded = 13; + +begin + Result := False; + Count := 0; + while (Position + Count < CodeLen) and + (Code[Position + Count] >= '0') and + (Code[Position + Count] <= '9') do + Inc (Count); + if Count > BytesNeeded then + Result := True; +end; + +function TStPDF417Barcode.GoodForTextCompaction ( + Position : Integer; + CodeLen : Integer; + var Count : Integer) : Boolean; + + function IsGoodTextValue (const v : Char) : Boolean; {!!.01} + begin {!!.01} + if v > #127 then {!!.01} + Result := False {!!.01} + else if TStPDF417TextCompaction[Integer (v)].Value >= 0 then {!!.01} + Result := True {!!.01} + else {!!.01} + Result := False; {!!.01} + end; {!!.01} + +const + BytesNeeded = 5; + +begin + Result := False; + Count := 0; + while (Position + Count < CodeLen) and {!!.01} + (IsGoodTextValue (Code[Position + Count])) and {!!.01} + (Count <= BytesNeeded) do {!!.01} + Inc (Count); + if (Count > BytesNeeded) or + ((Position + Count >= CodeLen) and (Count > 0)) then + Result := True; +end; + +procedure TStPDF417Barcode.RenderToResolution (var OutBitmap : TBitmap; + ResX : Integer; + ResY : Integer; + var SizeX : Integer; + var SizeY : Integer); +var + OldBarWidth : Integer; + OldWidth : Integer; + OldHeight : Integer; + CurResX : Integer; + CurResY : Integer; + MultX : Extended; + MultY : Extended; + +begin + OldBarWidth := BarWidth; + OldWidth := Width; + OldHeight := Height; + SizeX := Width; + SizeY := Height; + try + if (ResX <> 0) and (ResY <> 0) then begin + GetCurrentResolution (CurResX, CurResY); + MultX := ResX / CurResX; + MultY := ResY / CurResY; + FBarWidth := Trunc (FBarWidth * MultX); + FBitmap.Width := Trunc (FBitmap.Width * MultX); + FBitmap.Height := Trunc (FBitmap.Height * MultY); + SizeX := FBitmap.Width; + SizeY := FBitmap.Height; + end; + FBitmap.Canvas.Font.PixelsPerInch := OutBitmap.Canvas.Font.PixelsPerInch; + GenerateBarcodeBitmap (FBitmap.Width, FBitmap.Height); + OutBitmap.Width := SizeX; + OutBitmap.Height := SizeY; + OutBitmap.Canvas.CopyRect (Rect (0, 0, SizeX, SizeY), FBitmap.Canvas, + Rect (0, 0, SizeX, SizeY)); + finally + FBarWidth := OldBarWidth; + FBitmap.Width := OldWidth; + FBitmap.Height := OldHeight; + GenerateBarcodeBitmap (Width, Height); + end; +end; + +procedure TStPDF417Barcode.SetBarHeight (const v : Integer); +begin + if (v < 1) and (BarHeightToWidth = 0) and (not RelativeBarHeight) then + raise E2DBarcodeError.Create (StENeedBarHeight); + if v < 0 then + raise E2DBarcodeError.Create (StEBadBarWidth); + inherited SetBarHeight (v); +end; + +procedure TStPDF417Barcode.SetBarHeightToWidth (const v : Integer); +begin + if (v = 0) and (BarHeight = 0) and (not RelativeBarHeight) then + raise E2DBarcodeError.Create (StENeedBarHeight); + inherited SetBarHeightToWidth (v); +end; + +procedure TStPDF417Barcode.SetBarWidth (const v : Integer); +begin + if v < 1 then + raise E2DBarcodeError.Create (StEBadBarHeight); + inherited SetBarWidth (v); +end; + +procedure TStPDF417Barcode.SetPDF417ECCLevel (const v : TStPDF417ECCLevels); +var + NewLevel : Integer; + OldLevel : Integer; + +begin + NewLevel := -1; + case v of + ecAuto : NewLevel := -1; + ecLevel0 : NewLevel := 0; + ecLevel1 : NewLevel := 1; + ecLevel2 : NewLevel := 2; + ecLevel3 : NewLevel := 3; + ecLevel4 : NewLevel := 4; + ecLevel5 : NewLevel := 5; + ecLevel6 : NewLevel := 6; + ecLevel7 : NewLevel := 7; + ecLevel8 : NewLevel := 8; + end; + + if NewLevel <> FECCLevel then begin + OldLevel := FECCLevel; + try + FECCLevel := NewLevel; + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FECCLevel := OldLevel; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStPDF417Barcode.SetRelativeBarHeight (const v : Boolean); +begin + if (not v) and (BarHeightToWidth = 0) and (BarHeight = 0) then + raise E2DBarcodeError.Create (StENeedBarHeight); + inherited SetRelativeBarHeight (v); +end; + +procedure TStPDF417Barcode.SetTruncated (const v : Boolean); +var + OldTruncated : Boolean; + +begin + if v <> FTruncated then begin + OldTruncated := FTruncated; + try + FTruncated := v; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FTruncated := OldTruncated; + try + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +function TStPDF417Barcode.IsNumericString (const S : string) : boolean; +var + i : integer; + LenS : integer; + +begin + {note: an assertion test for ConvertToBase900} + Result := false; + LenS := length(S); + if (LenS = 0) or (LenS > 45) then + Exit; + for i := 1 to LenS do + if not (('0' <= S[i]) and (S[i] <= '9')) then + Exit; + Result := true; +end; + +procedure TStPDF417Barcode.SetNumColumns (const v : Integer); +var + OldNumColumns : Integer; + +begin + if (v < 0) or (v > 30) then + raise E2DBarcodeError.Create (StEBadNumCols); + if v <> FNumColumns then begin + OldNumColumns := FNumColumns; + try + if v < 0 then + FNumColumns := 0 + else + FNumColumns := v; + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FNumColumns := OldNumColumns; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStPDF417Barcode.SetNumRows (const v : Integer); +var + OldNumRows : Integer; + +begin + if (v < 0) or (v > 90) then + raise E2DBarcodeError.Create (StEBadNumRows); + if v <> FNumRows then begin + OldNumRows := FNumRows; + try + if v < 0 then + FNumRows := 0 + else + FNumRows := v; + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FNumRows := OldNumRows; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStPDF417Barcode.TextToCodewords; +var + i : Integer; + CodeLen : Integer; + CurrentMode : TStDataMode; + Count : Integer; + First : Boolean; + +const + TextCompaction = 900; + PadCodeword = 900; + +begin + First := True; + for i := 0 to 2700 do + FCodewords[i] := PadCodeword; + FNumCodewords := 1; { There will always be a length codeword } + i := 1; + + CodeLen := Length (Code); + if CodeLen = 0 then + Exit; + + if GoodForNumericCompaction (i, CodeLen, Count) then + CurrentMode := dmNumeric + else if GoodForTextCompaction (i, CodeLen, Count) then + CurrentMode := dmText + else + CurrentMode := dmBinary; + + while i < CodeLen do begin + case CurrentMode of + dmBinary : + EncodeBinary (i, CodeLen); + dmText : + if First then + EncodeText (i, CodeLen); + dmNumeric : + EncodeNumeric (i, CodeLen); + end; + + if GoodForNumericCompaction (i, CodeLen, Count) then + CurrentMode := dmNumeric + else if GoodForTextCompaction (i, CodeLen, Count) then begin + if not First then + AddCodeword (TextCompaction); + CurrentMode := dmText; + EncodeText (i, CodeLen); {!!.01} + end else + CurrentMode := dmBinary; + First := False; + end; +end; + +{ TStMaxiCodeBarcode } + +constructor TStMaxiCodeBarcode.Create (AOwner : TComponent); +begin + inherited Create (AOwner); + + FMode := cmMode4; + FHighlight := False; + FShowCodewords := False; + FShowAll := False; + FAutoScale := True; + FBarWidth := 0; + FBarHeight := 0; + FHorPixelsPerMM := 4; + FVerPixelsPerMM := 4; + FMaxiHexWidth := 9; + FMaxiHexHeight := 9; + FMaxiHexVOffset := -2; + FMaxiHexHOffset := 4; + FCarrierCountryCode := 0; + FCarrierServiceClass := 0; + FCarrierPostalCode := '000000000'; + + GetSizes; + + Width := 121; + Height := 129; + + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); +end; + +procedure TStMaxiCodeBarcode.AddCodeword (Value : Integer); +begin + if FNumCodewords <= 144 then + FMessage[FNumCodewords] := Value; + Inc (FNumCodewords); +end; + +function TStMaxiCodeBarcode.CalculateBarCodeWidth ( + PaintableWidth : Integer) : Integer; +begin + Result := Round (30 * FMaxiHexWidth + FMaxiHexHOffset); +end; + +function TStMaxiCodeBarcode.CalculateBarCodeHeight ( + PaintableHeight : Integer) : Integer; +begin + Result := Round (33 * FMaxiHexHeight + 33 * FMaxiHexVOffset); +end; + +procedure TStMaxiCodeBarcode.DrawBarcode; + + function IsBitOn (Value : Byte; Bit : Byte) : Boolean; + begin + Result := ((Value shr Bit) and $01) <> $00; + end; + +const + { + The MaxBits array is arranged to match the hex layout of the MaxiCode + Barcode. + + -2 identifies the (light) module at the center of the finder pattern, + -1 identifies modules which are always dark, + 0 identifies modules which are always light, and + Positive numbers indicate the bitnumber of the cell. + } + MaxBits : array [0..32] of array [0..29] of Integer = +(( 122,121,128,127,134,133,140,139,146,145,152,151,158,157,164,163,170,169,176,175,182,181,188,187,194,193,200,199, -1, -1 ), + ( 124,123,130,129,136,135,142,141,148,147,154,153,160,159,166,165,172,171,178,177,184,183,190,189,196,195,202,201,817, 0 ), + ( 126,125,132,131,138,137,144,143,150,149,156,155,162,161,168,167,174,173,180,179,186,185,192,191,198,197,204,203,819,818 ), + ( 284,283,278,277,272,271,266,265,260,259,254,253,248,247,242,241,236,235,230,229,224,223,218,217,212,211,206,205,820, 0 ), + ( 286,285,280,279,274,273,268,267,262,261,256,255,250,249,244,243,238,237,232,231,226,225,220,219,214,213,208,207,822,821 ), + ( 288,287,282,281,276,275,270,269,264,263,258,257,252,251,246,245,240,239,234,233,228,227,222,221,216,215,210,209,823, 0 ), + ( 290,289,296,295,302,301,308,307,314,313,320,319,326,325,332,331,338,337,344,343,350,349,356,355,362,361,368,367,825,824 ), + ( 292,291,298,297,304,303,310,309,316,315,322,321,328,327,334,333,340,339,346,345,352,351,358,357,364,363,370,369,826, 0 ), + ( 294,293,300,299,306,305,312,311,318,317,324,323,330,329,336,335,342,341,348,347,354,353,360,359,366,365,372,371,828,827 ), + ( 410,409,404,403,398,397,392,391, 80, 79, -1, -1, 14, 13, 38, 37, 3, 0, 45, 44,110,109,386,385,380,379,374,373,829, 0 ), + ( 412,411,406,405,400,399,394,393, 82, 81, 41, -1, 16, 15, 40, 39, 4, 0, 0, 46,112,111,388,387,382,381,376,375,831,830 ), + ( 414,413,408,407,402,401,396,395, 84, 83, 42, 0, 0, 0, 0, 0, 6, 5, 48, 47,114,113,390,389,384,383,378,377,832, 0 ), + ( 416,415,422,421,428,427,104,103, 56, 55, 17, 0, 0, 0, 0, 0, 0, 0, 21, 20, 86, 85,434,433,440,439,446,445,834,833 ), + ( 418,417,424,423,430,429,106,105, 58, 57, 0, 0, 0, 0, 0, 0, 0, 0, 23, 22, 88, 87,436,435,442,441,448,447,835, 0 ), + ( 420,419,426,425,432,431,108,107, 60, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 90, 89,438,437,444,443,450,449,837,836 ), + ( 482,481,476,475,470,469, 49, -1, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 54, 53,464,463,458,457,452,451,838, 0 ), + ( 484,483,478,477,472,471, 50, 0, -1, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, -1, 0,466,465,460,459,454,453,840,839 ), + ( 486,485,480,479,474,473, 52, 51, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, 43,468,467,462,461,456,455,841, 0 ), + ( 488,487,494,493,500,499, 98, 97, 62, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 92, 91,506,505,512,511,518,517,843,842 ), + ( 490,489,496,495,502,501,100, 99, 64, 63, 0, 0, 0, 0, 0, 0, 0, 0, 29, 28, 94, 93,508,507,514,513,520,519,844, 0 ), + ( 492,491,498,497,504,503,102,101, 66, 65, 18, 0, 0, 0, 0, 0, 0, 0, 19, 30, 96, 95,510,509,516,515,522,521,846,845 ), + ( 560,559,554,553,548,547,542,541, 74, 73, 33, 0, 0, 0, 0, 0, 0, 11, 68, 67,116,115,536,535,530,529,524,523,847, 0 ), + ( 562,561,556,555,550,549,544,543, 76, 75, -1, 0, 8, 7, 36, 35, 12, -1, 70, 69,118,117,538,537,532,531,526,525,849,848 ), + ( 564,563,558,557,552,551,546,545, 78, 77, -1, 34, 10, 9, 26, 25, 0, -1, 72, 71,120,119,540,539,534,533,528,527,850, 0 ), + ( 566,565,572,571,578,577,584,583,590,589,596,595,602,601,608,607,614,613,620,619,626,625,632,631,638,637,644,643,852,851 ), + ( 568,567,574,573,580,579,586,585,592,591,598,597,604,603,610,609,616,615,622,621,628,627,634,633,640,639,646,645,853, 0 ), + ( 570,569,576,575,582,581,588,587,594,593,600,599,606,605,612,611,618,617,624,623,630,629,636,635,642,641,648,647,855,854 ), + ( 728,727,722,721,716,715,710,709,704,703,698,697,692,691,686,685,680,679,674,673,668,667,662,661,656,655,650,649,856, 0 ), + ( 730,729,724,723,718,717,712,711,706,705,700,699,694,693,688,687,682,681,676,675,670,669,664,663,658,657,652,651,858,857 ), + ( 732,731,726,725,720,719,714,713,708,707,702,701,696,695,690,689,684,683,678,677,672,671,666,665,660,659,654,653,859, 0 ), + ( 734,733,740,739,746,745,752,751,758,757,764,763,770,769,776,775,782,781,788,787,794,793,800,799,806,805,812,811,861,860 ), + ( 736,735,742,741,748,747,754,753,760,759,766,765,772,771,778,777,784,783,790,789,796,795,802,801,808,807,814,813,862, 0 ), + ( 738,737,744,743,750,749,756,755,762,761,768,767,774,773,780,779,786,785,792,791,798,797,804,803,810,809,816,815,864,863 )); + + ColorTable : array [0..11] of TColor = ($bbffff, $ffbbff, $ffffbb, $bbbbff, + $bbffbb, $ffbbbb, $a0cbff, $a0ffcb, + $ffa0cb, $cba0ff, $ffcba0, $cbffa0); +var + i : Integer; + j : Integer; + XPos : Integer; + YPos : Integer; + RowOffset : Extended; + ByteNum : Integer; + BitOffset : Integer; + +begin + + FBitmap.Canvas.Brush.Color := Color; + FBitmap.Canvas.Pen.Width := 1; + + YPos := 0; + RowOffset := 0; + + for i := 0 to 32 do begin + for j := 0 to 29 do begin + XPos := Round (j * FMaxiHexWidth + RowOffset); + if FHighlight then begin + FBitmap.Canvas.Pen.Color := Color; + FBitmap.Canvas.Brush.Color := Color; + end; + + ByteNum := MaxBits[i, j]; + if ByteNum = -1 then begin + if FHighlight then + FBitmap.Canvas.Pen.Color := $505050; + DrawHex (XPos, YPos); + if FHighlight then + FBitmap.Canvas.Pen.Color := Color; + end else if ByteNum > 0 then begin + BitOffset := ((ByteNum - 1) mod 6); + ByteNum := (ByteNum - 1) div 6 {+ 1}; { Codeword 1 is the mode } + if FHighlight then begin + if not FShowCodewords then + case ByteNum of + 0 : FBitmap.Canvas.Pen.Color := ColorTable[0]; + 1..9 : FBitmap.Canvas.Pen.Color := ColorTable[1]; + 10..19 : FBitmap.Canvas.Pen.Color := ColorTable[2]; + 20..87 : FBitmap.Canvas.Pen.Color := ColorTable[3]; + 89..103 : FBitmap.Canvas.Pen.Color := ColorTable[4]; + 104..144 : FBitmap.Canvas.Pen.Color := ColorTable[5]; + end + else + FBitmap.Canvas.Pen.Color := ColorTable[ByteNum mod 12]; + FBitmap.Canvas.Brush.Color := FBitmap.Canvas.Pen.Color; + DrawHex (XPos, YPos); + FBitmap.Canvas.Pen.Color := Color; + FBitmap.Canvas.Brush.Color := Color; + end; + if IsBitOn (FCodewords[ByteNum], 5 - BitOffset) then + DrawHex (XPos, YPos) + else if FShowAll then + DrawHex (XPos, YPos); + end; + end; + RowOffset := FMaxiHexHOffset - RowOffset; + YPos := Round (((i + 1) * FMaxiHexHeight) * 0.8660254); + end; + + DrawFinder; +end; + +procedure TStMaxiCodeBarcode.DrawFinder; +var + CenterX : Integer; + CenterY : Integer; + +begin + CenterX := Round (BarCodeRect.Left + 14.5 * FMaxiHexWidth); + CenterY := BarCodeRect.Top + Round (16.5 * FMaxiHexHeight * 0.8660254); + FBitmap.Canvas.Brush.Color := BackgroundColor; + FBitmap.Canvas.Pen.Width := Round (FMaxiHexWidth + FMaxiHexVOffset); + FBitmap.Canvas.Ellipse ( + CenterX - Round (FMaxiHexWidth) * 4, + CenterY - Round (FMaxiHexHeight) * 4, + CenterX + Round (FMaxiHexWidth) * 4, + CenterY + Round (FMaxiHexHeight) * 4); + FBitmap.Canvas.Ellipse ( + CenterX - Round (FMaxiHexWidth * 2.5), + CenterY - Round (FMaxiHexHeight * 2.5), + CenterX + Round (FMaxiHexWidth * 2.5), + CenterY + Round (FMaxiHexHeight * 2.5)); + FBitmap.Canvas.Ellipse ( + CenterX - Round (FMaxiHexWidth), + CenterY - Round (FMaxiHexHeight), + CenterX + Round (FMaxiHexWidth), + CenterY + Round (FMaxiHexHeight)); + + if FHighlight then begin + FBitmap.Canvas.Pen.Width := 1; + FBitmap.Canvas.Pen.Color := clRed; + FBitmap.Canvas.MoveTo (CenterX, 0); + FBitmap.Canvas.LineTo (CenterX, Height); + FBitmap.Canvas.MoveTo (0, CenterY); + FBitmap.Canvas.LineTo (Width, CenterY); + end; + + FBitmap.Canvas.Pen.Width := 1; + FBitmap.Canvas.Brush.Color := Color; +end; + +procedure TStMaxiCodeBarcode.DrawHex (XPos, YPos : Integer); +var + XOffset : Integer; + YOffset : Integer; + HexWidth : Integer; + HexHeight : Integer; + Border : Extended; + +begin + XOffset := BarCodeRect.Left + XPos; + YOffset := BarCodeRect.Top + YPos; + Border := ((FMaxiHexWidth + 1) / 8) + 1; + if FMaxiHexWidth >= 4 then begin + XOffset := Round (XOffset + Border); + YOffset := Round (YOffset + Border); + HexWidth := Round (FMaxiHexWidth - Border); + HexHeight := Round (FMaxiHexHeight - Border); + end else begin + HexWidth := Round (FMaxiHexWidth); + HexHeight := Round (FMaxiHexHeight); + end; + + if (HexWidth < 4) or (HexHeight < 4) then + { Ellipses look better at poorer resolutions } + FBitmap.Canvas.Ellipse (XOffset, YOffset, + XOffset + HexWidth, YOffset + HexHeight) + else begin + { Better resolution, draw a hex } + FBitmap.Canvas.MoveTo (XOffset + HexWidth div 2, + YOffset); + FBitmap.Canvas.LineTo (XOffset + HexWidth, + YOffset + HexHeight div 4); + FBitmap.Canvas.LineTo (XOffset + HexWidth, + YOffset + HexHeight - (HexHeight div 4)); + FBitmap.Canvas.LineTo (XOffset + HexWidth div 2, + YOffset + HexHeight); + FBitmap.Canvas.LineTo (XOffset, + YOffset + HexHeight - (HexHeight div 4)); + FBitmap.Canvas.LineTo (XOffset, + YOffset + HexHeight div 4); + FBitmap.Canvas.LineTo (XOffset + HexWidth div 2, + YOffset); + + FBitmap.Canvas.FloodFill (XOffset + HexWidth div 2, + YOffset + HexWidth div 2, + BackgroundColor, + fsSurface); + end; +end; + +procedure TStMaxiCodeBarcode.GenerateCodewords; +begin + TextToCodewords; +end; + +procedure TStMaxiCodeBarcode.GenerateECC; + { Calculate the ECC codes for MaxiCode } + + function GFSum (a : Integer; b : Integer) : Integer; + { Sum of two numbers in Galois field arithmetic } + begin + Result := a xor b; + end; + + function GfDifference (a : Integer; b : Integer) : Integer; + { difference between two numbers in Galois field arithmetic (included for + completeness) } + begin + Result := a xor b; + end; + + function GFProduct (a : Integer; b : Integer) : Integer; + { Product of two numbers in Galois field arithmetic } + begin + if (a = 0) or (b = 0) then + Result := 0 + else + Result := FAntiLog[(FLog[a] + FLog[b]) mod (StMaxiCodeGaloisField - 1)]; + end; + + function GFQuotient (a : Integer; b : Integer) : Integer; + { Division of two numbers in Galois field arithmetic (included for + completeness ) } + begin + if b = 0 then + Result := 1 - StMaxiCodeGaloisField + else if a = 0 then + Result := 0 + else + Result := FAntiLog[(FLog[a] - FLog[b] + + (StMaxiCodeGaloisField - 1)) mod (StMaxiCodeGaloisField - 1)]; + end; + + procedure FillLogArrays (StMaxiCodeGaloisField : Integer; + StMaxiCodeECCPoly : Integer); + { Populate the log and antilog tables for Galois field arithmetic } + var + i : Integer; + + begin + FLog[0] := 1 - StMaxiCodeGaloisField; + FAntiLog[0] := 1; + for i := 1 to StMaxiCodeGaloisField - 1 do begin + FAntiLog[i] := FAntiLog[i - 1] * 2; + if FAntiLog[i] >= StMaxiCodeGaloisField then + FAntiLog[i] := FAntiLog[i] xor StMaxiCodeECCPoly; + FLog[FAntiLog[i]] := i; + end; + end; + + procedure CalculateECCCodes (var Data : TStMaxiCodeECCData; + Polynomial : TStMaxiCodeECCPoly; + IStart : TStMaxiCodeECCInterleave); + { Calculate the Reed-Solomon error correcting codes (ECC) for MaxiCode. + Basically, this is the equivalent of taking the Data as a series of + coefficients to a polynomial (that has the lowest power the same as the + highest power of the generating polynomial) and dividing it by the + generating polynomial using Galois field arithmetic. Get the remainder of + this division and use that as the Reed Solomon error correcting codes } + + const + { Generating polynomials } + GPrimary : array [0..10] of Integer = + (46, 44, 49, 3, 2, 57, 42, 39, 28, 31, 1); + GEnhanced : array [0..28] of Integer = + (28, 11, 20, 7, 43, 9, 41, 34, 49, 46, 37, 40, 55, 34, 45, 61, 13, 23, + 29, 22, 10, 35, 55, 41, 10, 53, 45, 22, 1); + GStandard : array [0..20] of Integer = + (59, 23, 19, 31, 33, 38, 17, 22, 48, 15, 36, 57, 37, 22, 8, 27, 33, 11, + 44, 23, 1); + + var + BRegisters : TStMaxiCodeECCData; { Works space for calculating RS ECC } + DataPos : Integer; { Position for data read/writes } + i : Integer; + j : Integer; + SumFromLast : Integer; { Result of input data + Last BReg } + GenPolyMult : Integer; { Input data (SumFromLast) * gen poly } + NumCodewords : Integer; { Number of ECC codewords to generate } + Interleaved : Boolean; { Read all data or alternate chars } + StartingPos : Integer; { Where to start reading from } + DataLength : Integer; { Amount of data to read } + OutDataPos : Integer; { Where to write ECC to } + + begin + { Intialize where to get data, write data, what poly to use, etc.. based + from the Polynomial used and whether or not the even characters or + odd characters are being encoded. } + case Polynomial of + epStandard : + { Standard Error Correction } + begin + NumCodewords := 20; + Interleaved := True; + if IStart = imOdd then begin + StartingPos := 20; + OutDataPos := 104; + end else begin + StartingPos := 21; + OutDataPos := 105; + end; + DataLength := 42; + end; + epEnhanced : + begin + { Enhanced Error Correction } + NumCodewords := 28; + Interleaved := True; + if IStart = imOdd then begin + StartingPos := 20; + OutDataPos := 88; + end else begin + StartingPos := 21; + OutDataPos := 89; + end; + DataLength := 34; + end + else begin + { Primary Message } + NumCodewords := 10; + Interleaved := False; + StartingPos := 0; + OutDataPos := 10; + DataLength := 10; + end; + end; + + { Initialize all the BRegisters } + for i := 0 to StMaxMaxiCodeECCDataSize do + BRegisters[i] := 0; + + { Calculate the Log and AntiLog tables } + FillLogArrays (StMaxiCodeGaloisField, StMaxiCodeECCPoly); + + DataPos := StartingPos; + + { Divide the polynomials and store the results in the BRegisters } + for i := 0 to DataLength - 1 do begin + SumFromLast := GFSum (BRegisters[NumCodewords - 1], Data[DataPos]); + for j := NumCodewords - 1 downto 0 do begin + case Polynomial of + epStandard : + GenPolyMult := GFProduct (SumFromLast, GStandard[j]); + epEnhanced : + GenPolyMult := GFProduct (SumFromLast, GEnhanced[j]); + else + GenPolyMult := GFProduct (SumFromLast, GPrimary[j]); + end; + if j > 0 then + BRegisters[j] := GFSum (BRegisters[j - 1], GenPolyMult) + else + BRegisters[j] := GenPolyMult; + end; + if Interleaved then + Inc (DataPos, 2) + else + Inc (DataPos); + end; + + { Write the ECC values back into the data } + DataPos := OutDataPos; + for i := NumCodewords - 1 downto 0 do begin + Data[DataPos] := BRegisters[i]; + if Interleaved then + Inc (DataPos, 2) + else + Inc (DataPos); + end; + end; + +begin + { Calculate ECC codes for MaxiCode } + + CalculateECCCodes (FCodewords, epPrimary, imNone); + if Mode = cmMode5 then begin + CalculateECCCodes (FCodewords, epEnhanced, imEven); + CalculateECCCodes (FCodewords, epEnhanced, imOdd); + end else begin + CalculateECCCodes (FCodewords, epStandard, imEven); + CalculateECCCodes (FCodewords, epStandard, imOdd); + end; +end; + +procedure TStMaxiCodeBarcode.GetNextCharacter (var NewChar : Integer; + var Codeword : Boolean; + var Position : Integer; + CodeLen : Integer); +var + WorkNum : Integer; + +begin + NewChar := 0; + Codeword := False; + + if Position <= CodeLen then begin + if (FCode[Position] = '\') and + (Position < CodeLen) then begin + case FCode[Position + 1] of + '0'..'9' : begin + try + NewChar := StrToInt (Copy (FCode, Position + 1, 3)); + Inc (Position, 4); + except + NewChar := 0; + Inc (Position, 4); + end; + end; + 'C', 'c' : begin + try + Codeword := True; + NewChar := StrToInt (Copy (FCode, Position + 2, 2)); + Inc (Position, 4); + except + NewChar := 0; + Inc (Position, 4); + end; + end; + 'E', 'e' : begin + if UpperCase (Copy (FCode, Position + 1, 3)) = 'EOT' then begin + NewChar := 4; + Inc (Position, 4); + end else + try + WorkNum := StrToInt (Copy (FCode, Position + 1, 6)); + AddCodeword (27); + Codeword := True; + Inc (Position, 8); + if (WorkNum >= 0) and (WorkNum <= 31) then begin + NewChar := WorkNum; + end else if (WorkNum >= 32) and (WorkNum <= 1023) then begin + AddCodeword ($20 or (WorkNum div 64)); + NewChar := WorkNum mod 64; + end else if (WorkNum >= 1024) and (WorkNum <= 32767) then begin + AddCodeword ($30 or (WorkNum div 4096)); + WorkNum := WorkNum mod 4096; + AddCodeword (WorkNum div 64); + NewChar := WorkNum mod 64; + end else if (WorkNum >= 32768) and (WorkNum <= 999999) then begin + AddCodeword ($38 or (WorkNum div 262144)); + WorkNum := WorkNum mod 262144; + AddCodeword (WorkNum div 64); + WorkNum := WorkNum mod 4096; + AddCodeword (WorkNum div 64); + NewChar := WorkNum mod 64; + end else + raise E2DBarcodeError.Create (StEGLIOutOfRange); + except + on EConvertError do begin + NewChar := Byte (FCode[Position]); + Inc (Position); + end; + end; + end; + 'F', 'f', 'G', 'g', 'N', 'n', 'R', 'r' : begin + if Position < CodeLen - 1 then begin + if (FCode[Position + 2] = 'S') or + (FCode[Position + 2] = 's') then begin + case FCode[Position + 1] of + 'F', 'f' : NewChar := 28; + 'G', 'g' : NewChar := 29; + 'N', 'n' : begin + NewChar := 31; + Codeword := True; + end; + 'R', 'r' : NewChar := 30; + end; + Inc (Position, 3); + end else begin + NewChar := Byte (FCode[Position]); + Inc (Position); + end; + end else begin + NewChar := Byte (FCode[Position]); + Inc (Position); + end; + end; + 'X', 'x' : begin + try + NewChar := StrToInt ('$' + Copy (FCode, Position + 2, 2)); + Inc (Position, 4); + except + NewChar := 0; + Inc (Position, 4); + end; + end; + '\' : begin + NewChar := Byte (FCode[Position]); + Inc (Position, 2); + end; + else begin + NewChar := Byte (FCode[Position]); + Inc (Position); + end; + end; + end else begin + NewChar := Byte (FCode[Position]); + Inc (Position); + end; + end; +end; + +procedure TStMaxiCodeBarcode.GetSizes; +var + ResX : Integer; + ResY : Integer; + +begin + ResX := GetDeviceCaps (FBitmap.Canvas.Handle, LOGPIXELSX); + ResY := GetDeviceCaps (FBitmap.Canvas.Handle, LOGPIXELSY); + GetSizesEx (ResX, ResY); +end; + +procedure TStMaxiCodeBarcode.GetSizesEx (ResX : Integer; ResY : Integer); +begin + if FAutoScale then begin + FMaxiHexWidth := (ResX * 1.003937) / 29; { Width is 1.00" } + FMaxiHexHeight := (ResY * 0.959449) /29; { Height is 0.96" } + FMaxiHexVOffset := -1 * (FMaxiHexHeight / 6); + FMaxiHexHOffset := FMaxiHexWidth / 2; + end else begin + if BarWidth <> 0 then + FMaxiHexWidth := BarWidth + else + FMaxiHexWidth := (FHorPixelsPerMM * 27) / 29; + if BarHeight <> 0 then + FMaxiHexHeight := BarHeight + else + FMaxiHexHeight := Round (FVerPixelsPerMM * 25) / 29; + FMaxiHexVOffset := -1 * (FMaxiHexHeight / 6); + FMaxiHexHOffset := FMaxiHexWidth / 2; + end; +end; + +procedure TStMaxiCodeBarcode.PlotCell (Row : Integer; Col : Integer); +var + XPos : Integer; + YPos : Integer; + +begin + YPos := Round (Row * FMaxiHexHeight + Row * FMaxiHexVOffset); + if (Row mod 2) <> 0 then + XPos := Round (FMaxiHexHOffset + FMaxiHexWidth * Col) + else + XPos := Round (FMaxiHexWidth * Col); + DrawHex (XPos, YPos); +end; + +procedure TStMaxiCodeBarcode.RenderToResolution (var OutBitmap : TBitmap; + ResX : Integer; + ResY : Integer; + var SizeX : Integer; + var SizeY : Integer); +var + OldBarWidth : Integer; + OldBarHeight : Integer; + OldHorPixelsPerMM : Extended; + OldVerPixelsPerMM : Extended; + OldWidth : Integer; + OldHeight : Integer; + CurResX : Integer; + CurResY : Integer; + MultX : Extended; + MultY : Extended; + OldPPI : Integer; + +begin + OldBarWidth := BarWidth; + OldBarHeight := BarHeight; + OldHorPixelsPerMM := FHorPixelsPerMM; + OldVerPixelsPerMM := FVerPixelsPerMM; + OldWidth := Width; + OldHeight := Height; + SizeX := Width; + SizeY := Height; + try + if (ResX <> 0) and (ResY <> 0) then begin + GetCurrentResolution (CurResX, CurResY); + MultX := ResX / CurResX; + MultY := ResY / CurResY; + + FBarWidth := Trunc (FBarWidth * MultX); + FBarHeight := Trunc (FBarHeight * MultX); + FHorPixelsPerMM := FHorPixelsPerMM * MultX; + FVerPixelsPerMM := FVerPixelsPerMM * MultX; + GetSizesEx (ResX, ResY); + FBitmap.Width := Trunc (FBitmap.Width * MultX); + FBitmap.Height := Trunc (FBitmap.Height * MultY); + + SizeX := FBitmap.Width; + SizeY := FBitmap.Height; + end; + OldPPI := FBitmap.Canvas.Font.PixelsPerInch; + try + FBitmap.Canvas.Font.PixelsPerInch := OutBitmap.Canvas.Font.PixelsPerInch; + GenerateBarcodeBitmap (FBitmap.Width, FBitmap.Height); + finally + FBitmap.Canvas.Font.PixelsPerInch := OldPPI; + end; + OutBitmap.Width := SizeX; + OutBitmap.Height := SizeY; + OutBitmap.Canvas.CopyRect (Rect (0, 0, SizeX, SizeY), FBitmap.Canvas, + Rect (0, 0, SizeX, SizeY)); + finally + FBarWidth := OldBarWidth; + FBarHeight := OldBarHeight; + FHorPixelsPerMM := OldHorPixelsPerMM; + FVerPixelsPerMM := OldVerPixelsPerMM; + FBitmap.Width := OldWidth; + FBitmap.Height := OldHeight; + GetSizes; + GenerateBarcodeBitmap (Width, Height); + end; +end; + +procedure TStMaxiCodeBarcode.SetAutoScale (const v : Boolean); +var + OldAutoScale : Boolean; + +begin + if v <> FAutoScale then begin + OldAutoScale := FAutoScale; + try + if (BarHeight = 0) and (HorPixelsPerMM = 0) and (not v) then + raise E2DBarcodeError.Create (StENeedHorz); + if (BarWidth = 0) and (VerPixelsPerMM = 0) and (not v) then + raise E2DBarcodeError.Create (StENeedVert); + FAutoScale := v; + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FAutoScale := OldAutoScale; + try + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStMaxiCodeBarcode.SetBarHeight (const v : Integer); +begin + if (v = 0) and (VerPixelsPerMM = 0) and (not AutoScale) then + raise E2DBarcodeError.Create (StENeedVert); + inherited SetBarHeight (v); + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; +end; + +procedure TStMaxiCodeBarcode.SetBarWidth (const v : Integer); +begin + if (v = 0) and (HorPixelsPerMM = 0) and (not AutoScale) then + raise E2DBarcodeError.Create (StENeedHorz); + inherited SetBarWidth (v); + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; +end; + +procedure TStMaxiCodeBarcode.SetCarrierCountryCode (const v : Integer); +var + OldCarrierCountryCode : Integer; + +begin + if v <> FCarrierCountryCode then begin + OldCarrierCountryCode := FCarrierCountryCode; + try + FCarrierCountryCode := v; + if (FMode = cmMode2) or (FMode = cmMode3) then begin + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + end; + except + on E2DBarcodeError do begin + FCarrierCountryCode := OldCarrierCountryCode; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStMaxiCodeBarcode.SetCarrierPostalCode (const v : string); +var + OldCarrierPostalCode : string; + +begin + if v <> FCarrierPostalCode then begin + OldCarrierPostalCode := FCarrierPostalCode; + try + FCarrierPostalCode := v; + if (FMode = cmMode2) or (FMode = cmMode3) then begin + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + end; + except + on E2DBarcodeError do begin + FCarrierPostalCode := OldCarrierPostalCode; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStMaxiCodeBarcode.SetCarrierServiceClass (const v : Integer); +var + OldCarrierServiceClass : Integer; + +begin + if v <> FCarrierServiceClass then begin + OldCarrierServiceClass := FCarrierServiceClass; + try + FCarrierServiceClass := v; + if (FMode = cmMode2) or (FMode = cmMode3) then begin + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + end; + except + on E2DBarcodeError do begin + FCarrierServiceClass := OldCarrierServiceClass; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStMaxiCodeBarcode.SetHorPixelsPerMM (const v : Extended); +var + OldHorPixelsPerMM : Extended; + +begin + if v <> FHorPixelsPerMM then begin + if (v = 0) and (BarWidth = 0) and (not AutoScale) then + raise E2DBarcodeError.Create (StENeedHorz); + OldHorPixelsPerMM := FHorPixelsPerMM; + try + FHorPixelsPerMM := v; + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FHorPixelsPerMM := OldHorPixelsPerMM; + try + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStMaxiCodeBarcode.SetMode (const v : TStMaxiCodeMode); +var + OldMode : TStMaxiCodeMode; + +begin + if v <> FMode then begin + OldMode := Mode; + try + FMode := v; + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FMode := OldMode; + try + GenerateCodewords; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStMaxiCodeBarcode.SetVerPixelsPerMM (const v : Extended); +var + OldVerPixelsPerMM : Extended; + +begin + if v <> FVerPixelsPerMM then begin + if (v = 0) and (BarHeight = 0) and (not AutoScale) then + raise E2DBarcodeError.Create (StENeedVert); + OldVerPixelsPerMM := FVerPixelsPerMM; + try + FVerPixelsPerMM := v; + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + FVerPixelsPerMM := OldVerPixelsPerMM; + try + GetSizes; + GenerateBarcodeBitmap (Width, Height); + Invalidate; + except + on E2DBarcodeError do begin + end; + end; + raise + end; + end; + end; +end; + +procedure TStMaxiCodeBarcode.TextToCodewords; + + + function FindCodeSet (Value : Char) : TStMaxiCodeCodeSet; + begin + Result := csCodeSetA; + while Result < csNone do begin + if StMaxiCodeCodeSets[Result][Integer (Value)] <> -1 then + Exit; + Inc (Result); + end; + Result := csNone; + end; + + function ChangeCodeSet (CurrentMode : TStMaxiCodeCodeSet; + NewMode : TStMaxiCodeCodeSet; + Value : Char; + UseShift : Boolean; + UseTwoShift : Boolean; + UseThreeShift : Boolean) : TStMaxiCodeCodeSet; + const + ShiftAB = 59; + ShiftAC = 60; + ShiftAD = 61; + ShiftAE = 62; + LatchAB = 63; + + Shift2BA = 56; + Shift3BA = 57; + ShiftBA = 59; + ShiftBC = 60; + ShiftBD = 61; + ShiftBE = 62; + LatchBA = 63; + + LatchCA = 58; + LockC = 60; + ShiftCD = 61; + ShiftCE = 62; + LatchCB = 63; + + LatchDA = 58; + ShiftDC = 60; + LockD = 61; + ShiftDE = 62; + LatchDB = 63; + + LatchEA = 58; + ShiftEC = 60; + ShiftED = 61; + LockE = 62; + LatchEB = 63; + + begin + if UseShift then + Result := CurrentMode + else + Result := NewMode; + + case CurrentMode of + csCodeSetA : + case NewMode of + csCodeSetB : + { A -> B } + if UseShift then + AddCodeword (ShiftAB) + else + AddCodeword (LatchAB); + csCodeSetC : + { A -> C } + begin + AddCodeword (ShiftAC); + if not UseShift then + AddCodeword (LockC); + end; + csCodeSetD : + { A -> D } + begin + AddCodeword (ShiftAD); + if not UseShift then + AddCodeword (LockD); + end; + csCodeSetE : + { A -> E } + begin + AddCodeword (ShiftAE); + if not UseShift then + AddCodeword (LockE); + end; + end; + + csCodeSetB : + case NewMode of + csCodeSetA : + { B -> A } + if UseThreeShift then + AddCodeword (Shift3BA) + else if UseTwoShift then + AddCodeword (Shift2BA) + else if UseShift then + AddCodeword (ShiftBA) + else + AddCodeword (LatchBA); + csCodeSetC : + { B -> C } + begin + AddCodeword (ShiftBC); + if not UseShift then + AddCodeword (LockC); + end; + csCodeSetD : + { B -> D } + begin + AddCodeword (ShiftBD); + if not UseShift then + AddCodeword (LockD); + end; + csCodeSetE : + { B -> E } + begin + AddCodeword (ShiftBE); + if not UseShift then + AddCodeword (LockE); + end; + end; + + csCodeSetC : + case NewMode of + csCodeSetA : + { C -> A } + begin + AddCodeword (LatchCA); + Result := NewMode; + end; + csCodeSetB : + { C -> B } + begin + AddCodeword (LatchCB); + Result := NewMode; + end; + csCodeSetD : + { C -> D } + begin + AddCodeword (ShiftCD); + if not UseShift then + AddCodeword (LockD); + end; + csCodeSetE : + { C -> E } + begin + AddCodeword (ShiftCE); + if not UseShift then + AddCodeword (LockE); + end; + end; + + csCodeSetD : + case NewMode of + csCodeSetA : + { D -> A } + begin + AddCodeword (LatchDA); + Result := NewMode; + end; + csCodeSetB : + { D -> B } + begin + AddCodeword (LatchDB); + Result := NewMode; + end; + csCodeSetC : + { D -> C } + begin + AddCodeword (ShiftDC); + if not UseShift then + AddCodeword (LockC); + end; + csCodeSetE : + { D -> E } + begin + AddCodeword (ShiftDE); + if not UseShift then + AddCodeword (LockE); + end; + end; + + csCodeSetE : + case NewMode of + csCodeSetA : + { E -> A } + begin + AddCodeword (LatchEA); + Result := NewMode; + end; + csCodeSetB : + { E -> B } + begin + AddCodeword (LatchEB); + Result := NewMode; + end; + csCodeSetC : + { E -> C } + begin + AddCodeword (ShiftEC); + if not UseShift then + AddCodeword (LockC); + end; + csCodeSetD : + { E -> D } + begin + AddCodeword (ShiftED); + if not UseShift then + AddCodeword (LockD); + end; + end; + end; + end; + + procedure GetMessageCodewords; + var + CodeLen : Integer; + CurrentMode : TStMaxiCodeCodeSet; + UseShift : Boolean; + UseShift2 : Boolean; + UseShift3 : Boolean; + WorkMode : TStMaxiCodeCodeSet; + i : Integer; + Codeword : Boolean; + NewChar : Integer; + + begin + CodeLen := Length (Code); + if CodeLen = 0 then begin + for i := 0 to 144 do + AddCodeword (33); + Exit; + end; + CurrentMode := csCodeSetA; + i := 1; + while i <= CodeLen do begin + GetNextCharacter (NewChar, CodeWord, i, CodeLen); + if CodeWord then + AddCodeword (NewChar) + else if StMaxiCodeCodeSets[CurrentMode][NewChar] = -1 then begin + WorkMode := FindCodeSet (Char (NewChar)); + UseShift := False; + UseShift2 := False; + UseShift3 := False; + if i < CodeLen then begin + if StMaxiCodeCodeSets[CurrentMode][Integer (Code[i + 1])] <> -1 then + UseShift := True; + end; + CurrentMode := ChangeCodeSet (CurrentMode, WorkMode, Char (NewChar), + UseShift, UseShift2, UseShift3); + AddCodeword (StMaxiCodeCodeSets[WorkMode][NewChar]); + end else + AddCodeword (StMaxiCodeCodeSets[CurrentMode][NewChar]); + end; + + if (FNumCodewords > 68) and (FMode = cmMode5) then + raise E2DBarcodeError.Create (StECodeTooLarge) + else if FNumCodewords > 84 then + raise E2DBarcodeError.Create (StECodeTooLarge); + + if CodeLen < 144 then begin + if CurrentMode = csCodeSetC then begin + AddCodeword (58); + CurrentMode := csCodeSetA; + end else if CurrentMode = csCodeSetD then begin + AddCodeword (58); + CurrentMode := csCodeSetA; + end; + for i := FNumCodewords to 144 do begin + case CurrentMode of + csCodeSetA : + AddCodeword (33); + csCodeSetB : + AddCodeword (33); + csCodeSetE : + AddCodeword (28); + end; + end; + end; + end; + + procedure MergeCodewords; + begin + case FMode of + cmMode2 : + System.Move (FMessage, FCodewords[20], 84); + cmMode3 : + System.Move (FMessage, FCodewords[20], 84); + cmMode4 : + begin + System.Move (FMessage, FCodeWords[1], 9); + System.Move (FMessage[9], FCodewords[20], 84); + end; + cmMode5 : + begin + System.Move (FMessage, FCodeWords[1], 9); + System.Move (FMessage[9], FCodewords[20], 68); + end; + cmMode6 : + System.Move (FMessage, FCodewords[20], 84); + end; + end; + + function IsNumericPostalCode : Boolean; + var + PostalLen : Integer; + i : Integer; + + begin + Result := True; + i := 1; + PostalLen := Length (FCarrierPostalCode); + while (i <= PostalLen) do + if (FCarrierPostalCode[i] < '0') or + (FCarrierPostalCode[i] > '9') then begin + Result := False; + i := PostalLen + 1; + end else + Inc (i); + end; + + procedure EncodeCarrierInfo; + + { Encodation of the carrier information requires some fairly bizarre + bit manipulation + + Codewords:--------> 111111 + 111111222222333333444444555555666666777777888888999999000000 C + 012345012345012345012345012345012345012345012345012345012345012345 W + num: ppMMMMppppppppppppppppppppppppllppppccllllccccccssssccssssssEEE... + an: ppMMMMppppppppppppppppppppppppppppppccppppccccccssssccssssssEEE... + 123456789012345678901234567890123456789012345678901234567890123456 B + Bits: -----> 111111111122222222223333333333444444444455555555556666666 i + t + MMMM = Mode + pppp = Postal Code + ll = Postal Code Length + cccc = Country Code + ssss = Service Class + EEEE = ECC Codes + + For pppp, ll, cccc and ssss, the MSB is on the right. + } + + var + WorkNum : Integer; + WorkStr : string; + i : Integer; + + begin + for WorkNum := 2 to 10 do + FCodewords[WorkNum] := 0; + FCodewords[0] := FCodewords[0] and $0f; + + if FCodewords[0] = $02 then begin + { Format numeric postal code } + { Format the postal code length } + WorkNum := Length (FCarrierPostalCode); + FCodewords[6] := (WorkNum and $3c) shr 2; + FCodewords[5] := (WorkNum and $03) shl 4; + { Format the postal code } + try + WorkNum := StrToInt (FCarrierPostalCode); + except + on EConvertError do + raise E2DBarcodeError.Create (StEBadPostalCode); + end; + FCodewords[5] := FCodewords[5] or ((WorkNum shr 26) and $0f); + FCodewords[4] := (WorkNum shr 20) and $3f; + FCodewords[3] := (WorkNum shr 14) and $3f; + FCodewords[2] := (WorkNum shr 8) and $3f; + FCodewords[1] := (WorkNum shr 2) and $3f; + FCodewords[0] := FCodewords[0] or ((WorkNum and $03) shl 4); + end else begin + { Format alphanumeric postal code } + WorkStr := UpperCase (FCarrierPostalCode) + ' '; + for i := 0 to 5 do begin + WorkNum := StMaxiCodeCodeSets[csCodeSetA][Integer (WorkStr[6 - i])]; + if WorkNum < 0 then + WorkNum := StMaxiCodeCodeSets[csCodeSetA][32]; { Use a space } + FCodewords[i] := FCodewords[i] or ((WorkNum and $03) shl 4); + FCodewords[i + 1] := FCodewords[i + 1] or ((WorkNum and $3c) shr 2); + end; + end; + + { Format country code } + WorkNum := FCarrierCountryCode; + FCodewords[8] := (WorkNum shr 8) and $03; + FCodewords[7] := (WorkNum shr 2) and $3f; + FCodewords[6] := FCodewords[6] or ((WorkNum and $03) shl 4); + + { Format service class } + WorkNum := FCarrierServiceClass; + FCodewords[9] := (WorkNum and $3f0) shr 4; + FCodewords[8] := FCodewords[8] or ((WorkNum and $0f) shl 2); + end; + +var + i : Integer; + +begin + for i := 0 to 144 do begin + FCodewords[i] := 0; + FMessage[i] := 0; + end; + + FNumCodewords := 0; + + { Encode the primary message and set the FNumCodewords to the begining + of the secondary message } + + case FMode of + cmMode2, cmMode3 : + if IsNumericPostalCode then + FCodewords[0] := $02 + else + FCodewords[0] := $03; + cmMode4 : + FCodewords[0] := $04; + cmMode5 : + FCodewords[0] := $05; + cmMode6 : + FCodewords[0] := $06; + end; + + if (FMode = cmMode2) or (FMode = cmMode3) then + EncodeCarrierInfo; + + GetMessageCodewords; + MergeCodewords; + GenerateECC; + FNumCodewords := 144; + + FTotalCodewords := 144; + if FMode = cmMode5 then + FUsedECCCodewords := 66 + else + FUsedECCCodewords := 50; + case FMode of + cmMode2 : + FUsedCodewords := FNumCodewords + 10; + cmMode3 : + FUsedCodewords := FNumCodewords + 10; + cmMode4 : + FUsedCodewords := FNumCodewords + 1; + cmMode5 : + FUsedCodewords := FNumCodewords + 1; + cmMode6 : + FUsedCodewords := FNumCodewords + 1; + end; + + FFreeCodewords := FTotalCodewords - FUsedCodewords - FUsedECCCodewords; + +end; + +end. + diff --git a/components/systools/source/run/stbarc.pas b/components/systools/source/run/stbarc.pas new file mode 100644 index 000000000..72fe2717d --- /dev/null +++ b/components/systools/source/run/stbarc.pas @@ -0,0 +1,2471 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StBarC.pas 4.04 *} +{*********************************************************} +{* SysTools: bar code components *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +unit StBarC; + +interface + +uses + {$IFDEF FPC} + LCLType, LCLIntf, LMessages, + {$ELSE} + Windows, Messages, + {$ENDIF} + Classes, ClipBrd, Controls, Graphics, SysUtils, + StBase, StConst; + +const + {.Z+} + bcMaxBarCodeLen = 255; + bcGuardBarAbove = True; + bcGuardBarBelow = True; + bcDefNarrowToWideRatio = 2; + {.Z-} + +type + TStBarKind = (bkSpace, bkBar, bkThreeQuarterBar, bkHalfBar, bkGuard, bkSupplement, bkBlankSpace); + {.Z+} + TStBarKindSet = set of TStBarKind; + TStDigitArray = array[1..bcMaxBarCodeLen] of Byte; + {.Z-} + + {.Z+} + TStBarData = class + FKind : TStBarKindSet; + FModules : Integer; + public + property Kind : TStBarKindSet + read FKind + write FKind; + property Modules : Integer + read FModules + write FModules; + end; + {.Z-} + + {.Z+} + TStBarCodeInfo = class + private + FBars : TList; + + function GetBars(Index : Integer) : TStBarData; + function GetCount : Integer; + + public + constructor Create; + virtual; + destructor Destroy; + override; + procedure Add(ModuleCount : Integer; BarKind : TStBarKindSet); + procedure Clear; + + property Bars[Index : Integer] : TStBarData + read GetBars; + default; + + property Count : Integer + read GetCount; + end; + {.Z-} + + TStBarCodeType = (bcUPC_A, bcUPC_E, bcEAN_8, bcEAN_13, + bcInterleaved2of5, bcCodabar, bcCode11, + bcCode39, bcCode93, bcCode128); + TStCode128CodeSubset = (csCodeA, csCodeB, csCodeC); + + TStBarCode = class(TGraphicControl) + protected {private} + {property variables} + {.Z+} + FAddCheckChar : Boolean; + FBarCodeType : TStBarCodeType; + FBarColor : TColor; + FBarToSpaceRatio : Double; + FBarNarrowToWideRatio : Integer; + FBarWidth : Double; {in mils} + FCode : String; + FCode128Subset : TStCode128CodeSubset; + FBearerBars : Boolean; + FShowCode : Boolean; + FShowGuardChars : Boolean; + FSupplementalCode : string; + FTallGuardBars : Boolean; + FExtendedSyntax : Boolean; + + {internal variables} + bcBarInfo : TStBarCodeInfo; + bcBarModWidth : Integer; {width of single bar} + bcCheckK : Integer; {"K" check character for use by Code11} + bcDigits : TStDigitArray; + bcDigitCount : Integer; + bcSpaceModWidth : Integer; {width of empty space between bars} + bcNormalWidth : Integer; + bcSpaceWidth : Integer; + bcSupplementWidth: Integer; + + {property methods} + function GetVersion : string; + procedure SetAddCheckChar(Value : Boolean); + procedure SetBarCodeType(Value : TStBarCodeType); + procedure SetBarColor(Value : TColor); + procedure SetBarToSpaceRatio(Value : Double); + procedure SetBarNarrowToWideRatio(Value: Integer); + procedure SetBarWidth(Value : Double); + procedure SetBearerBars(Value : Boolean); + procedure SetCode(const AValue : string); + procedure SetCode128Subset(Value : TStCode128CodeSubset); + procedure SetExtendedSyntax (const v : Boolean); + procedure SetShowCode(Value : Boolean); + procedure SetShowGuardChars(Value : Boolean); + procedure SetSupplementalCode(const Value : string); + procedure SetTallGuardBars(Value : Boolean); + procedure SetVersion(const Value : string); + + {internal methods} + procedure CalcBarCode; + procedure CalcBarCodeWidth; + function DrawBar(XPos, YPos, AWidth, AHeight : Integer) : Integer; + procedure DrawBarCode(const R : TRect); + function GetDigits(Characters : string) : Integer; + procedure PaintPrim(const R : TRect); + function SmallestLineWidth(PixelsPerInch : Integer) : Double; + + protected + procedure Loaded; override; + procedure Paint; override; + + public + constructor Create(AOwner : TComponent); override; + destructor Destroy; override; + {.Z-} + + procedure CopyToClipboard; + procedure GetCheckCharacters(const S : string; var C, K : Integer); + function GetBarCodeWidth(ACanvas : TCanvas) : Double; + procedure PaintToCanvas(ACanvas : TCanvas; ARect : TRect); + procedure PaintToCanvasSize(ACanvas : TCanvas; X, Y, H : Double); + procedure PaintToDC(DC : hDC; ARect : TRect); + procedure PaintToDCSize(DC : hDC; X, Y, W, H : Double); + procedure SaveToFile(const FileName : string); + function Validate(DisplayError : Boolean) : Boolean; + + published + {properties} + property Align; + property Anchors; + {$IFDEF FPC} + property BorderSpacing; + {$ENDIF} + property Color; + property Cursor; + property Enabled; + property Font; + property Height default 75; + property ParentColor; + property ParentFont; + property ParentShowHint; + property ShowHint; + property Visible; + property Width default 200; + + property AddCheckChar : Boolean + read FAddCheckChar + write SetAddCheckChar; + + property BarCodeType : TStBarCodeType + read FBarCodeType + write SetBarCodeType; + + property BarColor : TColor + read FBarColor + write SetBarColor; + + property BarToSpaceRatio : Double + read FBarToSpaceRatio + write SetBarToSpaceRatio; + + property BarNarrowToWideRatio : Integer + read FBarNarrowToWideRatio + write SetBarNarrowToWideRatio + default bcDefNarrowToWideRatio; + + property BarWidth : Double + read FBarWidth + write SetBarWidth; + + property BearerBars : Boolean + read FBearerBars + write SetBearerBars; + + property Code : string + read FCode + write SetCode; + + property Code128Subset : TStCode128CodeSubset + read FCode128Subset + write SetCode128Subset; + + property ExtendedSyntax : Boolean + read FExtendedSyntax write SetExtendedSyntax + default False; + + property ShowCode : Boolean + read FShowCode + write SetShowCode; + + property ShowGuardChars : Boolean + read FShowGuardChars + write SetShowGuardChars; + + property SupplementalCode : string + read FSupplementalCode + write SetSupplementalCode; + + property TallGuardBars : Boolean + read FTallGuardBars + write SetTallGuardBars; + + property Version : string + read GetVersion + write SetVersion + stored False; + + {events} + property OnClick; + property OnDblClick; + property OnMouseDown; + property OnMouseMove; + property OnMouseUp; + end; + + +implementation + +const + {left and right codes for UPC_A} + UPC_A_LeftHand : array[0..9] of string = + ('0001101', {0} + '0011001', {1} + '0010011', {2} + '0111101', {3} + '0100011', {4} + '0110001', {5} + '0101111', {6} + '0111011', {7} + '0110111', {8} + '0001011' {9} ); + + UPC_A_RightHand : array[0..9] of string = + ('1110010', {0} + '1100110', {1} + '1101100', {2} + '1000010', {3} + '1011100', {4} + '1001110', {5} + '1010000', {6} + '1000100', {7} + '1001000', {8} + '1110100' {9} ); + +const + UPC_E_OddParity : array[0..9] of string = + ('0001101', {0} + '0011001', {1} + '0010011', {2} + '0111101', {3} + '0100011', {4} + '0110001', {5} + '0101111', {6} + '0111011', {7} + '0110111', {8} + '0001011' {9} ); + + UPC_E_EvenParity : array[0..9] of string = + ('0100111', {0} + '0110011', {1} + '0011011', {2} + '0100001', {3} + '0011101', {4} + '0111001', {5} + '0000101', {6} + '0010001', {7} + '0001001', {8} + '0010111' {9} ); + +const + EAN_LeftHandA : array[0..9] of string = + ('0001101', {0} + '0011001', {1} + '0010011', {2} + '0111101', {3} + '0100011', {4} + '0110001', {5} + '0101111', {6} + '0111011', {7} + '0110111', {8} + '0001011' {9} ); + + EAN_LeftHandB : array[0..9] of string = + ('0100111', {0} + '0110011', {1} + '0011011', {2} + '0100001', {3} + '0011101', {4} + '0111001', {5} + '0000101', {6} + '0010001', {7} + '0001001', {8} + '0010111' {9} ); + +const + Interleaved_2of5 : array[0..9] of string = + ('00110', {0} + '10001', {1} + '01001', {2} + '11000', {3} + '00101', {4} + '10100', {5} + '01100', {6} + '00011', {7} + '10010', {8} + '01010' {9} ); + +const + Codabar : array[0..19] of string = + {BSBSBSB} {bar-space-bar-space-bar...} + ('0000011', {0} + '0000110', {1} + '0001001', {2} + '1100000', {3} + '0010010', {4} + '1000010', {5} + '0100001', {6} + '0100100', {7} + '0110000', {8} + '1001000', {9} + '0001100', {-} + '0011000', { $} + '1000101', {:} + '1010001', {/} + '1010100', {.} + '0010101', {+} + '0011010', {A} + '0101001', {B} + '0001011', {C} + '0001110' {D}); + +const + Code11 : array[0..11] of string = + {BSBSB} {bar-space-bar-space-bar...} {0-narrow, 1-wide} + ('00001', {0} + '10001', {1} + '01001', {2} + '11000', {3} + '00101', {4} + '10100', {5} + '01100', {6} + '00011', {7} + '10010', {8} + '10000', {9} + '00100', {-} + '00110'); {stop character} + +const + Code39 : array[0..43] of string = + {BSBSBSBSB} {bar-space-bar-space-bar...} {0-narrow, 1-wide} + ('000110100', {0} + '100100001', {1} + '001100001', {2} + '101100000', {3} + '000110001', {4} + '100110000', {5} + '001110000', {6} + '000100101', {7} + '100100100', {8} + '001100100', {9} + '100001001', {A} + '001001001', {B} + '101001000', {C} + '000011001', {D} + '100011000', {E} + '001011000', {F} + '000001101', {G} + '100001100', {H} + '001001100', {I} + '000011100', {J} + '100000011', {K} + '001000011', {L} + '101000010', {M} + '000010011', {N} + '100010010', {O} + '001010010', {P} + '000000111', {Q} + '100000110', {R} + '001000110', {S} + '000010110', {T} + '110000001', {U} + '011000001', {V} + '111000000', {W} + '010010001', {X} + '110010000', {Y} + '011010000', {Z} + '010000101', {-} + '110000100', {.} + '011000100', {SPACE} + '010101000', { $} + '010100010', {/} + '010001010', {+} + '000101010', {%} + '010010100'); {*} + +const + Code93 : array[0..46] of string = + {BSBSBS} {bar-space-bar-space-bar...} {0-narrow, 1-wide} + ('131112', {0} + '111213', {1} + '111312', {2} + '111411', {3} + '121113', {4} + '121212', {5} + '121311', {6} + '111114', {7} + '131211', {8} + '141111', {9} + '211113', {A} + '211212', {B} + '211311', {C} + '221112', {D} + '221211', {E} + '231111', {F} + '112113', {G} + '112212', {H} + '112311', {I} + '122112', {J} + '132111', {K} + '111123', {L} + '111222', {M} + '111321', {N} + '121122', {O} + '131121', {P} + '212112', {Q} + '212211', {R} + '211122', {S} + '211221', {T} + '221121', {U} + '222111', {V} + '112122', {W} + '112221', {X} + '122121', {Y} + '123111', {Z} + '121131', {-} + '311112', {.} + '311211', {SPACE} + '321111', { $} + '112131', {/} + '113121', {+} + '211131', {%} + '121221', {($)} + '312111', {(%)} + '311121', {(/)} + '122211'); {(+)} + + Code93Map : array[#0..#127] of string = + {Circle Code} {ASCII Code 93 } + ('%U', {NL (%)U } + '$A', {SH ($)A } + '$B', {SX ($)B } + '$C', {EX ($)C } + '$D', {ET ($)D } + '$E', {EQ ($)E } + '$F', {AK ($)F } + '$G', {BL ($)G } + '$H', {BS ($)H } + '$I', {HT ($)I } + '$J', {LF ($)J } + '$K', {VT ($)K } + '$L', {FF ($)L } + '$M', {CR ($)M } + '$N', {SO ($)N } + '$O', {SI ($)O } + '$P', {DL ($)P } + '$Q', {D1 ($)Q } + '$R', {D2 ($)R } + '$S', {D3 ($)S } + '$T', {D4 ($)T } + '$U', {NK ($)U } + '$V', {SY ($)V } + '$W', {EB ($)W } + '$X', {CN ($)X } + '$Y', {EM ($)Y } + '$Z', {SB ($)Z } + '%A', {EC (%)A } + '%B', {FS (%)B } + '%C', {GS (%)C } + '%D', {RS (%)D } + '%E', {US (%)E } + ' ', {Space Space } + '/A', {! (/)A } + '/B', {" (/)B } + '/C', {# (/)C } + '$', { $ (/)D or $} + '%', {% (/)E or %} + '/F', {& (/)F } + '/G', {' (/)G } + '/H', {( (/)H } + '/I', {) (/)I } + '/J', {* (/)J } + ' +', {+ (/)K or +} + '/L', {, (/)L } + '-', {- (/)M or -} + '.', {. (/)N or .} + '/', {/ (/)O or /} + '0', {0 (/)P or 0} + '1', {1 (/)Q or 1} + '2', {2 (/)R or 2} + '3', {3 (/)S or 3} + '4', {4 (/)T or 4} + '5', {5 (/)U or 5} + '6', {6 (/)V or 6} + '7', {7 (/)W or 7} + '8', {8 (/)X or 8} + '9', {9 (/)Y or 9} + '/Z', {: (/)Z } + '%F', {; (%)F } + '%G', {< (%)G } + '%H', {= (%)H } + '%I', {> (%)I } + '%J', {? (%)J } + '%V', { (%)V } + 'A', {A A } + 'B', {B B } + 'C', {C C } + 'D', {D D } + 'E', {E E } + 'F', {F F } + 'G', {G G } + 'H', {H H } + 'I', {I I } + 'J', {J J } + 'K', {K K } + 'L', {L L } + 'M', {M M } + 'N', {N N } + 'O', {O O } + 'P', {P P } + 'Q', {Q Q } + 'R', {R R } + 'S', {S S } + 'T', {T T } + 'U', {U U } + 'V', {V V } + 'W', {W W } + 'X', {X X } + 'Y', {Y Y } + 'Z', {Z Z } + '%K', {[ (%)K } + '%L', {\ (%)L } + '%M', {] (%)M } + '%N', {^ (%)N } + '%O', {_ (%)O } + '%W', {` (%)W } + '+A', {a (+)A } + '+B', {b (+)B } + '+C', {c (+)C } + '+D', {d (+)D } + '+E', {e (+)E } + '+F', {f (+)F } + '+G', {g (+)G } + '+H', {h (+)H } + '+I', {i (+)I } + '+J', {j (+)J } + '+K', {k (+)K } + '+L', {l (+)L } + '+M', {m (+)M } + '+N', {n (+)N } + '+O', {o (+)O } + '+P', {p (+)P } + '+Q', {q (+)Q } + '+R', {r (+)R } + '+S', {s (+)S } + '+T', {t (+)T } + '+U', {u (+)U } + '+V', {v (+)V } + '+W', {w (+)W } + '+X', {x (+)X } + '+Y', {y (+)Y } + '+Z', {z (+)Z } + '%P', {{ (%)P } + '%Q', {| (%)Q } + '%R', {}{ (%)R } + '%S', {~ (%)S } + '%T'); { DEL (%)T } + +const + Code128 : array[0..106] of string = + {BSBSBS} {Value CodeA CodeB CodeC} + ('212222', {0 SPACE SPACE 00} + '222122', {1 ! ! 01} + '222221', {2 " " 02} + '121223', {3 # # 03} + '121322', {4 $ $ 04} + '131222', {5 % % 05} + '122213', {6 & & 06} + '122312', {7 ' ' 07} + '132212', {8 ( ( 08} + '221213', {9 ) ) 09} + '221312', {10 * * 10} + '231212', {11 + + 11} + '112232', {12 , , 12} + '122132', {13 - - 13} + '122231', {14 . . 14} + '113222', {15 / / 15} + '123122', {16 0 0 16} + '123221', {17 1 1 17} + '223211', {18 2 2 18} + '221132', {19 3 3 19} + '221231', {20 4 4 20} + '213212', {21 5 5 21} + '223112', {22 6 6 22} + '312131', {23 7 7 23} + '311222', {24 8 8 24} + '321122', {25 9 9 25} + '321221', {26 : : 26} + '312212', {27 ; ; 27} + '322112', {28 < < 28} + '322211', {29 = = 29} + '212123', {30 > > 30} + '212321', {31 ? ? 31} + '232121', {32 @ @ 32} + '111323', {33 A A 33} + '131123', {34 B B 34} + '131321', {35 C C 35} + '112313', {36 D D 36} + '132113', {37 E E 37} + '132311', {38 F F 38} + '211313', {39 G G 39} + '231113', {40 H H 40} + '231311', {41 I I 41} + '112133', {42 J J 42} + '112331', {43 K K 43} + '132131', {44 L L 44} + '113123', {45 M M 45} + '113321', {46 N N 46} + '133121', {47 O O 47} + '313121', {48 P P 48} + '211331', {49 Q Q 49} + '231131', {50 R R 50} + '213113', {51 S S 51} + '213311', {52 T T 52} + '213131', {53 U U 53} + '311123', {54 V V 54} + '311321', {55 W W 55} + '331121', {56 X X 56} + '312113', {57 Y Y 57} + '312311', {58 Z Z 58} + '332111', {59 [ [ 59} + '314111', {60 \ \ 60} + '221411', {61 ] ] 61} + '431111', {62 ^ ^ 62} + '111224', {63 _ _ 63} + '111422', {64 NU ` 64} + '121124', {65 SH a 65} + '121421', {66 SX b 66} + '141122', {67 EX c 67} + '141221', {68 ET d 68} + '112214', {69 EQ e 69} + '112412', {70 AK f 70} + '122114', {71 BL g 71} + '122411', {72 BS h 72} + '142112', {73 HT i 73} + '142211', {74 LF j 74} + '241211', {75 VT k 75} + '221114', {76 FF l 76} + '413111', {77 CR m 77} + '241112', {78 SO n 78} + '134111', {79 SI o 79} + '111242', {80 DL p 80} + '121142', {81 D1 q 81} + '121241', {82 D2 r 82} + '114212', {83 D3 s 83} + '124112', {84 D4 t 84} + '124211', {85 NK u 85} + '411212', {86 SY v 86} + '421112', {87 EB w 87} + '421211', {88 CN x 88} + '212141', {89 EM y 89} + '214121', {90 SB z 90} + '412121', (*91 EC { 91*) + '111143', {92 FS 92} + '111341', (*93 GS } 93*) + '131141', {94 RS ~ 94} + '114113', {95 US DEL 95} + '114311', {96 FNC 3 FNC 3 96} {use #132} + '411113', {97 FNC 2 FNC 2 97} {use #131} + '411311', {98 SHIFT SHIFT 98} {use #130} + '113141', {99 CODE C CODE C 99} {use #135} + '114131', {100 CODE B FNC 4 CODE B} {use #134} + '311141', {101 FNC 4 CODE A CODE A} {use #133} + '411131', {102 FNC 1 FNC 1 FNC 1 } {use #130} + '211412', {103 CODE A} {use #136} + '211214', {104 CODE B} {use #137} + '211232', {105 CODE C} {use #138} + '2331112');{106 STOP} {use #139} + + +{*** helper routines ***} + +function RectWidth(const R : TRect) : Integer; +begin + Result := R.Right-R.Left; +end; + +function RectHeight(const R : TRect) : Integer; +begin + Result := R.Bottom-R.Top; +end; + + +{*** TStBarCodeInfo ***} + +procedure TStBarCodeInfo.Add(ModuleCount : Integer; BarKind : TStBarKindSet); +var + Bar : TStBarData; +begin + Bar := TStBarData.Create; + Bar.Modules := ModuleCount; + Bar.Kind := BarKind; + FBars.Add(Bar); +end; + +procedure TStBarCodeInfo.Clear; +var + I : Integer; +begin + for I := 0 to FBars.Count-1 do + TStBarData(FBars[I]).Free; + FBars.Clear; +end; + +constructor TStBarCodeInfo.Create; +begin + inherited Create; + + FBars := TList.Create; +end; + +destructor TStBarCodeInfo.Destroy; +begin + Clear; + FBars.Free; + FBars := nil; + + inherited Destroy; +end; + +function TStBarCodeInfo.GetBars(Index : Integer) : TStBarData; +begin + Result := FBars[Index]; +end; + +function TStBarCodeInfo.GetCount : Integer; +begin + Result := FBars.Count; +end; + + +{*** TStBarCode ***} + +procedure TStBarCode.CalcBarCode; +var + I, J, X : Integer; + CheckC : Integer; + CheckK : Integer; + CSP : string; + C : string; + C1, C2 : string; + + procedure AddCode(const S : string; AKind : TStBarKindSet); + var + I : Integer; + begin + for I := 1 to Length(S) do + if S[I] = '0' then + bcBarInfo.Add(1, AKind - [bkBar, bkThreeQuarterBar, bkHalfBar] + [bkSpace]) + else + bcBarInfo.Add(StrToInt(S[I]), AKind); + end; + + procedure AddECode(const Parity : string); + var + I : Integer; + begin + for I := 1 to Length(Parity) do begin + if Parity[I] = 'E' then + AddCode(UPC_E_EvenParity[bcDigits[I]], [bkBar]) + else + AddCode(UPC_E_OddParity[bcDigits[I]], [bkBar]); + end; + end; + + procedure AddSupCode(const Parity : string); + var + I : Integer; + begin + for I := 1 to Length(Parity) do begin + if Parity[I] = 'E' then + AddCode(UPC_E_EvenParity[bcDigits[I]], [bkThreeQuarterBar, bkSupplement]) + else + AddCode(UPC_E_OddParity[bcDigits[I]], [bkThreeQuarterBar, bkSupplement]); + if I < Length(Parity) then + AddCode('01', [bkThreeQuarterBar, bkSupplement]); + end; + end; + + procedure AddCodeModules(const S : string); + var + K : Integer; + begin + for K := 1 to Length(S) do begin + if Odd(K) then + bcBarInfo.Add(StrToInt(S[K]), [bkBar]) + else + bcBarInfo.Add(StrToInt(S[K]), [bkSpace]); + end; + end; + + procedure AddCodeWideNarrow(const S : string); + var + K : Integer; + begin + for K := 1 to Length(S) do begin + case S[K] of + '0' : if Odd(K) then + bcBarInfo.Add(1, [bkBar]) + else + bcBarInfo.Add(1, [bkSpace]); + '1' : if Odd(K) then + bcBarInfo.Add(FBarNarrowToWideRatio, [bkBar]) + else + bcBarInfo.Add(FBarNarrowToWideRatio, [bkSpace]); + end; + end; + end; + +begin + if csLoading in ComponentState then + Exit; + + bcBarInfo.Clear; + if Code = '' then + Exit; + + {get copy of code} + C := Code; + + {get digits} + case FBarCodeType of + bcUPC_A, bcUPC_E, bcEAN_8, bcEAN_13, bcCodabar, bcCode11, bcCode93 : + begin + bcDigitCount := GetDigits(C); + end; + bcInterleaved2of5 : + begin + {adjust odd length code} + if FAddCheckChar then begin + if not Odd(Length(C)) then + C := '0' + C; + end else begin + if Odd(Length(C)) then + C := '0' + C; + end; + bcDigitCount := GetDigits(C); + end; + bcCode39 : + begin + {add guard characters} + if C[1] <> '*' then + C := '*' + C; + if C[Length(C)] <> '*' then + C := C + '*'; + bcDigitCount := GetDigits(C); + end; + bcCode128 : + begin + {add start code} + if not (C[1] in [#136, #137, #138]) then + case FCode128Subset of + csCodeA : C := #136 + C; + csCodeB : C := #137 + C; + csCodeC : C := #138 + C; + end; + bcDigitCount := GetDigits(C); + end; + end; + + case FBarCodeType of + bcUPC_A : + begin + {get check digit} + if Length(C) = 11 then + GetCheckCharacters(C, CheckC, CheckK) + else + CheckC := bcDigits[12]; + + {encode left hand guard bars} + AddCode('101', [bkGuard, bkBar]); + + {first six characters as left hand characters} + for I := 1 to 6 do + AddCode(UPC_A_LeftHand[bcDigits[I]], [bkBar]); + + {center guard pattern} + AddCode('01010', [bkGuard, bkBar]); + + {last five data characters as right hand characters} + for I := 7 to 11 do + AddCode(UPC_A_RightHand[bcDigits[I]], [bkBar]); + + {check character} + AddCode(UPC_A_RightHand[CheckC], [bkBar]); + + {encode right hand guard bars} + AddCode('101', [bkGuard, bkBar]); + end; + bcUPC_E : + begin + {encode left hand guard bars, 101} + AddCode('101', [bkGuard, bkBar]); + GetCheckCharacters(C, CheckC, CheckK); + case CheckC of + 0 : AddECode('EEEOOO'); + 1 : AddECode('EEOEOO'); + 2 : AddECode('EEOOEO'); + 3 : AddECode('EEOOOE'); + 4 : AddECode('EOEEOO'); + 5 : AddECode('EOOEEO'); + 6 : AddECode('EOOOEE'); + 7 : AddECode('EOEOEO'); + 8 : AddECode('EOEOOE'); + 9 : AddECode('EOOEOE'); + end; + {encode right hand guard bars} + AddCode('010101', [bkGuard, bkBar]); + end; + bcEAN_8 : + begin + {get check digit} + if Length(C) = 7 then + GetCheckCharacters(C, CheckC, CheckK) + else + CheckC := bcDigits[8]; + + {encode left hand guard bars} + AddCode('101', [bkGuard, bkBar]); + {two flag two data characters, encoded as left hand A characters} + for I := 1 to 4 do + AddCode(EAN_LeftHandA[bcDigits[I]], [bkBar]); + {encode center guard bars} + AddCode('01010', [bkGuard, bkBar]); + {last three data characters, encoded as right hand characters} + for I := 5 to 7 do + AddCode(UPC_A_RightHand[bcDigits[I]], [bkBar]); + {check character} + AddCode(UPC_A_RightHand[CheckC], [bkBar]); + {encode right hand guard bars} + AddCode('101', [bkGuard, bkBar]); + end; + bcEAN_13 : + begin + {get check digit} + if Length(C) = 12 then + GetCheckCharacters(C, CheckC, CheckK) + else + CheckC := bcDigits[13]; + + {determine which left hand table to use based on first flag character} + {EAN refers to this as the 13th digit - counting from the right} + case bcDigits[1] of + { 12345} + 0 : CSP := 'AAAAAA'; + 1 : CSP := 'AABABB'; + 2 : CSP := 'AABBAB'; + 3 : CSP := 'AABBBA'; + 4 : CSP := 'ABAABB'; + 5 : CSP := 'ABBAAB'; + 6 : CSP := 'ABBBAA'; + 7 : CSP := 'ABABAB'; + 8 : CSP := 'ABABBA'; + 9 : CSP := 'ABBABA'; + end; + {encode left hand guard bars} + AddCode('101', [bkGuard, bkBar]); + {start with second flag character and next five data characters} + for I := 2 to 7 do + if CSP[I-1] = 'A' then + AddCode(EAN_LeftHandA[bcDigits[I]], [bkBar]) + else + AddCode(EAN_LeftHandB[bcDigits[I]], [bkBar]); + {encode center guard bars} + AddCode('01010', [bkGuard, bkBar]); + {encode last five data characters} + for I := 8 to 12 do + AddCode(UPC_A_RightHand[bcDigits[I]], [bkBar]); + {check character} + AddCode(UPC_A_RightHand[CheckC], [bkBar]); + {encode right hand guard bars} + AddCode('101', [bkGuard, bkBar]); + end; + bcInterleaved2of5 : + begin + {add check character} + if FAddCheckChar then begin + {get check digit} + GetCheckCharacters(C, CheckC, CheckK); + Inc(bcDigitCount); + bcDigits[bcDigitCount] := CheckC; + end; + + {encode left guard pattern} + bcBarInfo.Add(1, [bkGuard, bkBar]); + bcBarInfo.Add(1, [bkGuard, bkSpace]); + bcBarInfo.Add(1, [bkGuard, bkBar]); + bcBarInfo.Add(1, [bkGuard, bkSpace]); + + I := 1; + while I < bcDigitCount do begin + {take two characters at a time - odd as bars, even as spaces} + C1 := Interleaved_2of5[bcDigits[I]]; + C2 := Interleaved_2of5[bcDigits[I+1]]; + {interleave data} + for J := 1 to 5 do begin + if C1[J] = '1' then + bcBarInfo.Add(FBarNarrowToWideRatio, [bkBar]) {wide bar} + else + bcBarInfo.Add(1, [bkBar]); {narrow bar} + if C2[J] = '1' then + bcBarInfo.Add(FBarNarrowToWideRatio, [bkSpace]){wide space} + else + bcBarInfo.Add(1, [bkSpace]); {narrow space} + end; + Inc(I, 2); + end; + + {encode right guard pattern} + bcBarInfo.Add(FBarNarrowToWideRatio, + [bkGuard, bkBar]); {double-width bar} + bcBarInfo.Add(1, [bkGuard, bkSpace]); + bcBarInfo.Add(1, [bkGuard, bkBar]); + end; + bcCodabar : + begin + for I := 1 to bcDigitCount do begin + AddCodeWideNarrow(Codabar[bcDigits[I]]); + if I < bcDigitCount then + bcBarInfo.Add(1, [bkSpace]); + end; + end; + bcCode11 : + begin + AddCodeWideNarrow(Code11[11]); {start} + bcBarInfo.Add(1, [bkSpace]); + {add check characters} + if FAddCheckChar then begin + {get check digits} + GetCheckCharacters(C, CheckC, CheckK); + Inc(bcDigitCount); + bcDigits[bcDigitCount] := CheckC; + Inc(bcDigitCount); + bcDigits[bcDigitCount] := CheckK; + end; + + for I := 1 to bcDigitCount do begin + AddCodeWideNarrow(Code11[bcDigits[I]]); + bcBarInfo.Add(1, [bkSpace]); + end; + AddCodeWideNarrow(Code11[11]); {stop} + end; + bcCode39 : + begin + for I := 1 to bcDigitCount do begin + C1 := Code39[bcDigits[I]]; + for J := 1 to Length(C1) do begin + case C1[J] of + '0' : if Odd(J) then + bcBarInfo.Add(1, [bkBar]) + else + bcBarInfo.Add(1, [bkSpace]); + '1' : if Odd(J) then + bcBarInfo.Add(2, [bkBar]) + else + bcBarInfo.Add(2, [bkSpace]); + end; + end; + bcBarInfo.Add(1, [bkSpace]); + end; + end; + bcCode93 : + begin; + {start character} + AddCodeModules('111141'); + {add check characters} + if FAddCheckChar then begin + {get check digits} + GetCheckCharacters(C, CheckC, CheckK); + Inc(bcDigitCount); + bcDigits[bcDigitCount] := CheckC; + Inc(bcDigitCount); + bcDigits[bcDigitCount] := CheckK; + end; + for I := 1 to bcDigitCount do + AddCodeModules(Code93[bcDigits[I]]); + {stop character} + AddCodeModules('1111411'); + end; + bcCode128 : + begin + {add check character} + if FAddCheckChar then begin + GetCheckCharacters(C, CheckC, CheckK); + Inc(bcDigitCount); + bcDigits[bcDigitCount] := CheckC; + end; + {add stop code} + Inc(bcDigitCount); + bcDigits[bcDigitCount] := 106; + for I := 1 to bcDigitCount do + AddCodeModules(Code128[bcDigits[I]]); + end; + end; + + if FBarCodeType in [bcUPC_A, bcUPC_E, bcEAN_8, bcEAN_13] then begin + {add supplemental encodings if requested} + if Length(FSupplementalCode) in [2, 5] then begin + {get digits} + bcDigitCount := GetDigits(FSupplementalCode); + {7 spaces after primary code - 0000000} + AddCode('0000000', [bkThreeQuarterBar, bkBlankSpace]); + {encode left hand guard bars, 1011} + AddCode('1011', [bkThreeQuarterBar, bkSupplement]); + + if bcDigitCount = 2 then begin + {two digit supplement} + {determine parity table to use for each of the two characters} + X := bcDigits[1] * 10 + bcDigits[2]; + case X mod 4 of + 0 : AddSupCode('OO'); + 1 : AddSupCode('OE'); + 2 : AddSupCode('EO'); + 3 : AddSupCode('EE'); + end; + end else begin + {five digit supplement} + {determine the parity pattern to use for each of the five} + X := ((bcDigits[1] + bcDigits[3] + bcDigits[5])*3 + (bcDigits[2] + bcDigits[4])*9) mod 10; + case X of + 0 : AddSupCode('EEOOO'); + 1 : AddSupCode('EOEOO'); + 2 : AddSupCode('EOOEO'); + 3 : AddSupCode('EOOOE'); + 4 : AddSupCode('OEEOO'); + 5 : AddSupCode('OOEEO'); + 6 : AddSupCode('OOOEE'); + 7 : AddSupCode('OEOEO'); + 8 : AddSupCode('OEOOE'); + 9 : AddSupCode('OOEOE'); + end; + end; + end; + end; +end; + +procedure TStBarCode.CalcBarCodeWidth; +var + I : Integer; +begin + bcNormalWidth := 0; + bcSpaceWidth := 0; + bcSupplementWidth := 0; + for I := 0 to bcBarInfo.Count-1 do begin + if bkSpace in bcBarInfo[I].Kind then begin + if bkBlankSpace in bcBarInfo[I].Kind then + Inc(bcSpaceWidth, bcSpaceModWidth*bcBarInfo[I].Modules) + else if bkSupplement in bcBarInfo[I].Kind then + Inc(bcSupplementWidth, bcSpaceModWidth*bcBarInfo[I].Modules) + else + Inc(bcNormalWidth, bcSpaceModWidth*bcBarInfo[I].Modules) + end else begin + if bkBlankSpace in bcBarInfo[I].Kind then + Inc(bcSpaceWidth, bcBarModWidth*bcBarInfo[I].Modules) + else if bkSupplement in bcBarInfo[I].Kind then + Inc(bcSupplementWidth, bcBarModWidth*bcBarInfo[I].Modules) + else + Inc(bcNormalWidth, bcBarModWidth*bcBarInfo[I].Modules) + end; + end; +end; + +procedure TStBarCode.CopyToClipboard; +var + {$IFNDEF FPC} + MetaFile : TMetaFile; + MetaFileCanvas : TMetaFileCanvas; + {$ENDIF} + Bitmap : TBitmap; +begin + Clipboard.Clear; + Clipboard.Open; + try + {bitmap} + Bitmap := TBitmap.Create; + try + Bitmap.Width := ClientWidth; + Bitmap.Height := ClientHeight; + PaintToDC(Bitmap.Canvas.Handle, ClientRect); + Clipboard.Assign(Bitmap); + + {$IFNDEF FPC} + {metafile} + MetaFile := TMetaFile.Create; + try + MetaFileCanvas := TMetaFileCanvas.Create(MetaFile, 0); + try + MetaFile.Enhanced := True; + MetaFile.Width := ClientWidth; + MetaFile.Height := ClientHeight; + MetaFileCanvas.Draw(0, 0, Bitmap); + finally + MetaFileCanvas.Free; + end; + Clipboard.Assign(MetaFile); + finally + MetaFile.Free; + end; + {$ENDIF} + + finally + Bitmap.Free; + end + finally + Clipboard.Close; + end; +end; + +constructor TStBarCode.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + bcBarInfo := TStBarCodeInfo.Create; + + {defaults} + Color := clWhite; + SetInitialBounds(0, 0, 200, 75); + + FAddCheckChar := True; + FBarColor := clBlack; + FBarToSpaceRatio := 1; + FBarNarrowToWideRatio := bcDefNarrowToWideRatio; + FBarWidth := 12; + FShowCode := True; + FShowGuardChars := False; + FTallGuardBars := False; + FExtendedSyntax := False; + + FCode := '123456789012'; + CalcBarCode; +end; + +destructor TStBarCode.Destroy; +begin + bcBarInfo.Free; + bcBarInfo := nil; + + inherited Destroy; +end; + +function TStBarCode.DrawBar(XPos, YPos, AWidth, AHeight : Integer) : Integer; +begin + Canvas.Rectangle(XPos, YPos, XPos+AWidth, YPos+AHeight); + Result := XPos + AWidth; +end; + +procedure TStBarCode.DrawBarCode(const R : TRect); +var + I, X, Y : Integer; + CheckC : Integer; + CheckK : Integer; + TH, GA, TQ, BB : Integer; + BarCodeHeight : Integer; + BarCodeWidth : Integer; + PixelsPerInchX : Integer; + TR : TRect; + SmallestWidth : Double; + C : string; + Buf : array[0..512] of Char; +begin + Canvas.Brush.Color := FBarColor; + Canvas.Brush.Style := bsSolid; + + PixelsPerInchX := GetDeviceCaps(Canvas.Handle, LOGPIXELSX); + + {determine narrowest line width} + SmallestWidth := SmallestLineWidth(PixelsPerInchX); + + {find sizes for the BarCode elements} + bcBarModWidth := Round(FBarWidth/1000 * PixelsPerInchX); + if bcBarModWidth < FBarToSpaceRatio then + bcBarModWidth := Round(BarToSpaceRatio); + if bcBarModWidth < SmallestWidth then + bcBarModWidth := Round(SmallestWidth); + bcSpaceModWidth := Round(bcBarModWidth / FBarToSpaceRatio); + + {total width of BarCode and position within rect} + CalcBarCodeWidth; + BarCodeWidth := bcNormalWidth + bcSpaceWidth + bcSupplementWidth; + BarCodeHeight := RectHeight(R); + if BarCodeWidth < RectWidth(R) then + X := R.Left + (RectWidth(R)-BarCodeWidth) div 2 + else + X := R.Left; + Y := R.Top; + + {get text height} + TH := Canvas.TextHeight('Yg0'); + + {guard bar adjustment} + GA := (BarCodeHeight*10) div 100; {10% of bar height} + {but, not more than 1/4 of the font height} + if FShowCode and (GA > TH div 4) then + GA := TH div 4; + + {three quarter height bar adjustment} + TQ := BarCodeHeight div 4; + + {draw the text} + if FShowCode and (Code > '') then begin + C := Code; + {fill out invalid codes} + case FBarCodeType of + bcUPC_A : + begin + C := Copy(C, 1, 12); {truncate} + if Length(C) = 11 then begin + GetCheckCharacters(C, CheckC, CheckK); + C := C + IntToStr(CheckC); + end; + while Length(C) < 12 do + C := C + '0'; + end; + bcUPC_E : + begin + C := Copy(C, 1, 6); {truncate} + while Length(C) < 6 do + C := C + '0'; + end; + bcEAN_8 : + begin + C := Copy(C, 1, 8); {truncate} + if Length(C) = 7 then begin + GetCheckCharacters(C, CheckC, CheckK); + C := C + IntToStr(CheckC); + end; + while Length(C) < 8 do + C := C + '0'; + end; + bcEAN_13 : + begin + C := Copy(C, 1, 13); {truncate} + if Length(C) = 12 then begin + GetCheckCharacters(C, CheckC, CheckK); + C := C + IntToStr(CheckC); + end; + while Length(C) < 13 do + C := C + '0'; + end; + bcInterleaved2of5 : + begin + if Odd(Length(C)) then + C := '0' + C; + end; + bcCodabar : + begin + if not FShowGuardChars then + {strip leading and trailing characters} + C := Copy(C, 2, Length(C)-2); + end; + bcCode11 : + begin + end; + bcCode39 : + begin + {add guard characters} + if C[1] <> '*' then + C := '*' + C; + if C[Length(C)] <> '*' then + C := C + '*'; + if not FShowGuardChars then + {strip leading and trailing characters} + C := Copy(C, 2, Length(C)-2); + end; + bcCode93 : + begin + {remove non-printable characters} + for I := 1 to Length(C) do + if C[I] < ' ' then + C[I] := ' '; + end; + bcCode128 : + begin + {remove non-printable characters} + I := 1; + while I <= Length (C) do begin + if C[I] < ' ' then + C[I] := ' '; + if (i < Length (C)) and (ExtendedSyntax) then begin + if (C[I] = '\') and + (C[I + 1] in ['A', 'B', 'C', 'a', 'b', 'c']) then begin + C[I] := ' '; + C[I + 1] := ' '; + Inc (I); + end else if (C[I] = '\') and (C[I+1] = '\') then begin + C[I] := ' '; + Inc (I); + end; + end; + Inc (I); + end; + end; + end; + + Dec(BarCodeHeight, TH + (TH div 4)); + Canvas.Brush.Style := bsClear; + {guard bar adjustment - again} + GA := (BarCodeHeight*10) div 100; {10% of bar height} + {but, not more than 1/4 of the font height} + if FShowCode and (GA > TH div 4) then + GA := TH div 4; + {three quarter height bar adjustment} + TQ := BarCodeHeight div 4; + + if FBarCodeType = bcUPC_A then begin + {print first and last character to sides of symbol} + TR.Top := Y; + TR.Bottom := TR.Top + BarCodeHeight; + {left hand character} + Buf[0] := C[1]; + TR.Right := X; + TR.Left := X - 2 * Canvas.TextWidth(C[1]); + DrawText(Canvas.Handle, @Buf, 1, TR, DT_BOTTOM or DT_CENTER or DT_SINGLELINE); + {remove character from code to print} + C := Copy(C, 2, Length(C)-1); + + {right hand character - if no supplemental code} + if FSupplementalCode = '' then begin + Buf[0] := C[Length(C)]; + TR.Left := X + bcNormalWidth; + TR.Right := X + bcNormalWidth + 2 * Canvas.TextWidth(C[Length(C)]); + DrawText(Canvas.Handle, @Buf, 1, TR, DT_BOTTOM or DT_CENTER or DT_SINGLELINE); + {remove character from code to print} + C := Copy(C, 1, Length(C)-1); + end; + end; + + if FSupplementalCode > '' then begin + {draw supplemental code above the code} + TR.Top := Y + TQ - TH; + TR.Bottom := Y + BarCodeHeight; + TR.Left := X + bcNormalWidth + bcSpaceWidth; + TR.Right := TR.Left + bcSupplementWidth; + StrPLCopy(Buf, FSupplementalCode, Length(Buf)-1); + DrawText(Canvas.Handle, @Buf, StrLen(Buf), TR, DT_VCENTER or DT_CENTER); + end; + + TR := R; + TR.Top := R.Top + BarCodeHeight + (TH div 4); + TR.Left := X; + TR.Right := TR.Left + bcNormalWidth; + Canvas.Brush.Style := bsClear; + StrPLCopy(Buf, C, Length(Buf)-1); + DrawText(Canvas.Handle, @Buf, StrLen(Buf), TR, DT_VCENTER or DT_CENTER); + Canvas.Brush.Style := bsSolid; + Canvas.Brush.Color := FBarColor; + end; + + if (FBarCodeType = bcInterleaved2of5) and FBearerBars then begin + BB := 3 * bcBarModWidth; + {reduce height to allow for bearer bars} + Dec(BarCodeHeight, BB * 2); + {draw the bearer bars} + Canvas.Rectangle(X-bcBarModWidth, Y, + X+BarCodeWidth+bcBarModWidth, Y+BB); + Canvas.Rectangle(X-bcBarModWidth, Y+BarCodeHeight+BB, + X+BarCodeWidth+bcBarModWidth, Y+BarCodeHeight+BB*2); + {adjust top of BarCode} + Inc(Y, BB); + end; + + {draw the bar code} + for I := 0 to bcBarInfo.Count-1 do begin + if bkSpace in bcBarInfo[I].Kind then + Inc(X, bcSpaceModWidth*bcBarInfo[I].Modules) + else if (bkGuard in bcBarInfo[I].Kind) and FTallGuardBars then begin + if bcGuardBarAbove and bcGuardBarBelow then + X := DrawBar(X, Y-GA, bcBarModWidth*bcBarInfo[I].Modules, BarCodeHeight+2*GA) + else if bcGuardBarAbove then + X := DrawBar(X, Y-GA, bcBarModWidth*bcBarInfo[I].Modules, BarCodeHeight+GA) + else if bcGuardBarBelow then + X := DrawBar(X, Y, bcBarModWidth*bcBarInfo[I].Modules, BarCodeHeight+2*GA) + end else if (bkBar in bcBarInfo[I].Kind) or (bkGuard in bcBarInfo[I].Kind) then + X := DrawBar(X, Y, bcBarModWidth*bcBarInfo[I].Modules, BarCodeHeight) + else if (bkThreeQuarterBar in bcBarInfo[I].Kind) then + X := DrawBar(X, Y+TQ, bcBarModWidth*bcBarInfo[I].Modules, BarCodeHeight-TQ); + end; +end; + + {added} +function TStBarCode.GetBarCodeWidth(ACanvas : TCanvas) : Double; +var + PixelsPerInchX : Integer; + SmallestWidth : Double; +begin + PixelsPerInchX := GetDeviceCaps(ACanvas.Handle, LOGPIXELSX); + + {determine narrowest line width} + SmallestWidth := SmallestLineWidth(PixelsPerInchX); + + {find sizes for the BarCode elements} + bcBarModWidth := Round(FBarWidth/1000 * PixelsPerInchX); + if bcBarModWidth < FBarToSpaceRatio then + bcBarModWidth := Round(BarToSpaceRatio); + if bcBarModWidth < SmallestWidth then + bcBarModWidth := Round(SmallestWidth); + bcSpaceModWidth := Round(bcBarModWidth / FBarToSpaceRatio); + + CalcBarcodeWidth; + + {width in pixels (not counting text printed to left or right of code)} + Result := bcNormalWidth + bcSpaceWidth + bcSupplementWidth; + {return width of barcode in inches} + Result := Result / PixelsPerInchX; +end; + +procedure TStBarCode.GetCheckCharacters(const S : string; var C, K : Integer); +var + I : Integer; + C1 : Integer; + C2 : Integer; + St : string; +begin + C := -1; + K := -1; + St := S; + case FBarCodeType of + bcUPC_A : + begin + if Length(St) >= 11 then begin + {get digits} + GetDigits(St); + {determine check character} + C1 := (bcDigits[1] + bcDigits[3] + bcDigits[5] + bcDigits[7] + + bcDigits[9] + bcDigits[11]) * 3; + C2 := bcDigits[2] + bcDigits[4] + bcDigits[6] + + bcDigits[8] + bcDigits[10]; + C := 10 - ((C1 + C2) mod 10); + if C = 10 then + C := 0; + end; + end; + bcUPC_E : + begin + {get digits} + GetDigits(St); + {determine check character} + C1 := (bcDigits[2] + bcDigits[4] + bcDigits[6]) * 3; + C2 := bcDigits[1] + bcDigits[3] + bcDigits[5]; + C := 10 - ((C1 + C2) mod 10); + if C = 10 then + C := 0; + end; + bcEAN_8 : + begin + if Length(St) >= 7 then begin + {get digits} + GetDigits(St); + {determine check character} + C1 := (bcDigits[1] + bcDigits[3] + bcDigits[5] + bcDigits[7]) * 3; + C2 := bcDigits[2] + bcDigits[4] + bcDigits[6]; + C := 10 - ((C1 + C2) mod 10); + if C = 10 then + C := 0; + end; + end; + bcEAN_13 : + begin + if Length(St) >= 12 then begin + {get digits} + GetDigits(St); + {determine check character} + C1 := (bcDigits[2] + bcDigits[4] + bcDigits[6] + bcDigits[8] + + bcDigits[10] + bcDigits[12]) * 3; + C2 := bcDigits[1] + bcDigits[3] + bcDigits[5] + bcDigits[7] + + bcDigits[9] + bcDigits[11]; + C := 10 - ((C1 + C2) mod 10); + if C = 10 then + C := 0; + end; + end; + bcInterleaved2of5 : + begin + {get digits} + bcDigitCount := GetDigits(St); + + C1 := 0; + C2 := 0; + for I := 1 to bcDigitCount do + if Odd(I) then + C1 := C1 + bcDigits[I] {odd digits} + else + C2 := C2 + bcDigits[I]; {even digits} + C2 := C2 * 3; + + C := 10 - ((C1 + C2) mod 10); + if C = 10 then + C := 0; + end; + bcCodabar : + begin + {get digits} + bcDigitCount := GetDigits(St); + + C1 := 0; + for I := 1 to bcDigitCount do + C1 := C1 + bcDigits[I]; + + C := 16 - (C1 mod 16); + if C = 16 then + C := 0; + end; + bcCode11 : + begin + {get digits} + bcDigitCount := GetDigits(St); + C1 := 0; + for I := bcDigitCount downto 1 do + C1 := C1 + bcDigits[I]*(bcDigitCount-I+1); + C1 := C1 mod 11; {the "C" check character} + C2 := C1; + for I := bcDigitCount downto 1 do + C2 := C2 + bcDigits[I]*(bcDigitCount-I+2); + C2 := C2 mod 11; {the "K" check character} + K := C2; + C := C1; + end; + bcCode39 : + begin + {get digits} + bcDigitCount := GetDigits(St); + + C1 := 0; + for I := 1 to bcDigitCount do + C1 := C1 + bcDigits[I]; + + C := 43 - (C1 mod 43); + if C = 43 then + C := 0; + end; + bcCode93 : + begin + {get digits} + bcDigitCount := GetDigits(St); + C1 := 0; + for I := bcDigitCount downto 1 do + C1 := C1 + bcDigits[I]*(bcDigitCount-I+1); + C1 := C1 mod 47; {the "C" check character} + C2 := C1; + for I := bcDigitCount downto 1 do + C2 := C2 + bcDigits[I]*(bcDigitCount-I+2); + C2 := C2 mod 47; {the "K" check character} + K := C2; + C := C1; + end; + bcCode128 : + begin + {get digits} + bcDigitCount := GetDigits(St); + + C1 := bcDigits[1]; + for I := 2 to bcDigitCount do + C1 := C1 + bcDigits[I]*(I-1); + + C := C1 mod 103; + if C = 103 then + C := 0; + end; + end; +end; + +function TStBarCode.GetDigits(Characters : string) : Integer; + + procedure GetACode128CDigit (c : Char; var Index : Integer; + var bcDigitPos : Integer); + var + J : Integer; + + begin + case (c) of + #130 : bcDigits[bcDigitPos + 1] := 98; {rest are manufactured characters} + #131 : bcDigits[bcDigitPos + 1] := 97; + #132 : bcDigits[bcDigitPos + 1] := 96; + #133 : bcDigits[bcDigitPos + 1] := 98; + #134 : bcDigits[bcDigitPos + 1] := 100; + #135 : bcDigits[bcDigitPos + 1] := 99; + #136 : bcDigits[bcDigitPos + 1] := 103; + #137 : bcDigits[bcDigitPos + 1] := 104; + #138 : bcDigits[bcDigitPos + 1] := 105; + #139 : bcDigits[bcDigitPos + 1] := 106; + else + try + J := StrToInt (Copy (Characters, Index, 2)); + bcDigits[bcDigitPos + 1] := J; + Inc (Index); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + Inc (Index); + Inc (bcDigitPos); + end; + + procedure GetACode128ABDigit (c : Char; var Index : Integer; + var bcDigitPos : Integer); + begin + case c of + ' ' : bcDigits[bcDigitPos + 1] := 0; + '!' : bcDigits[bcDigitPos + 1] := 1; + '"' : bcDigits[bcDigitPos + 1] := 2; + '#' : bcDigits[bcDigitPos + 1] := 3; + '$' : bcDigits[bcDigitPos + 1] := 4; + '%' : bcDigits[bcDigitPos + 1] := 5; + '&' : bcDigits[bcDigitPos + 1] := 6; + '''' : bcDigits[bcDigitPos + 1] := 7; + '(' : bcDigits[bcDigitPos + 1] := 8; + ')' : bcDigits[bcDigitPos + 1] := 9; + '*' : bcDigits[bcDigitPos + 1] := 10; + '+' : bcDigits[bcDigitPos + 1] := 11; + ',' : bcDigits[bcDigitPos + 1] := 12; + '-' : bcDigits[bcDigitPos + 1] := 13; + '.' : bcDigits[bcDigitPos + 1] := 14; + '/' : bcDigits[bcDigitPos + 1] := 15; + '0'..'9' : bcDigits[bcDigitPos + 1] := 16 + Ord(c)-Ord('0'); + ':' : bcDigits[bcDigitPos + 1] := 26; + ';' : bcDigits[bcDigitPos + 1] := 27; + '<' : bcDigits[bcDigitPos + 1] := 28; + '=' : bcDigits[bcDigitPos + 1] := 29; + '>' : bcDigits[bcDigitPos + 1] := 30; + '?' : bcDigits[bcDigitPos + 1] := 31; + '@' : bcDigits[bcDigitPos + 1] := 32; + 'A'..'Z' : bcDigits[bcDigitPos + 1] := 33 + Ord(c)-Ord('A'); + '[' : bcDigits[bcDigitPos + 1] := 59; + '\' : bcDigits[bcDigitPos + 1] := 60; + ']' : bcDigits[bcDigitPos + 1] := 61; + '^' : bcDigits[bcDigitPos + 1] := 62; + '_' : bcDigits[bcDigitPos + 1] := 63; + #0, #31 : bcDigits[bcDigitPos + 1] := 64 + Ord(c); {control characters} + '`' : bcDigits[bcDigitPos + 1] := 64; + 'a'..'z' : bcDigits[bcDigitPos + 1] := 65 + Ord(c)-Ord('a'); + '{' : bcDigits[bcDigitPos + 1] := 91; + '|' : bcDigits[bcDigitPos + 1] := 92; + '}' : bcDigits[bcDigitPos + 1] := 93; + '~' : bcDigits[bcDigitPos + 1] := 94; + #130 : bcDigits[bcDigitPos + 1] := 98; {rest are manufactured characters} + #131 : bcDigits[bcDigitPos + 1] := 97; + #132 : bcDigits[bcDigitPos + 1] := 96; + #133 : bcDigits[bcDigitPos + 1] := 98; + #134 : bcDigits[bcDigitPos + 1] := 100; + #135 : bcDigits[bcDigitPos + 1] := 99; + #136 : bcDigits[bcDigitPos + 1] := 103; + #137 : bcDigits[bcDigitPos + 1] := 104; + #138 : bcDigits[bcDigitPos + 1] := 105; + #139 : bcDigits[bcDigitPos + 1] := 106; + else + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + Inc (Index); + Inc (bcDigitPos); + end; + + function CountCode128Digits (Index : Integer) : Integer; + begin + Result := 0; + while (Index <= Length (Characters)) and + (Characters[Index] >= '0') and (Characters[Index] <= '9') do begin + Inc (Result); + Inc (Index); + end; + end; + + function CheckCode128Digits (Index : Integer; CharsLen : Integer) : Boolean; + var + NumDigits : Integer; + begin + Result := False; + NumDigits := CountCode128Digits (Index); + if NumDigits mod 2 <> 0 then begin + Characters := Copy (Characters, 1, Index - 1) + + '0' + Copy (Characters, Index, CharsLen - Index + 1); + Result := True; + end; + end; + + function GetCode128Digits : Integer; + var + I : Integer; + RLen : Integer; + CurMode : TStCode128CodeSubset; + NeedCharCount : Boolean; + Skip : Boolean; + + begin + I := 1; + Result := Length (Characters); + RLen := 0; + CurMode := Self.Code128Subset; + NeedCharCount := Self.Code128Subset = csCodeC; + + while I <= Result do begin + if (NeedCharCount) and + (Characters[I] >= '0') and (Characters[I] <= '9') then begin + NeedCharCount := False; + if CheckCode128Digits (I, Result) then + Inc (Result); + end; + + Skip := False; + if (ExtendedSyntax) and (Characters[I] = '\') and + (I < Result) then begin + if ((Characters[I + 1] = 'A') or (Characters[I + 1] = 'a')) and + (CurMode <> csCodeA) then begin + Inc (RLen); + bcDigits[RLen] := 101; + CurMode := csCodeA; + Skip := True; + end else if ((Characters[I + 1] = 'B') or (Characters[I + 1] = 'b')) and + (CurMode <> csCodeB) then begin + Inc (RLen); + bcDigits[RLen] := 100; + CurMode :=csCodeB; + Skip := True; + end else if ((Characters[I + 1] = 'C') or (Characters[I + 1] = 'c')) and + (CurMode <> csCodeC) then begin + NeedCharCount := True; + Inc (RLen); + bcDigits[RLen] := 99; + CurMode := csCodeC; + Skip := True; + end else if (Characters[I + 1] = '\') then begin + GetACode128ABDigit ('\', I, RLen); + Skip := True; + end; + Inc (I); + end; + + if not Skip then + case CurMode of + csCodeC : + GetACode128CDigit (Characters[I], I, RLen); + else + GetACode128ABDigit (Characters[I], I, RLen); + end + else + Inc (I); + end; + Result := RLen; + end; + +var + I, J : Integer; + S : string; +begin + FillChar(bcDigits, SizeOf(bcDigits), #0); + Result := 0; + + case FBarCodeType of + bcUPC_A, bcUPC_E, bcEAN_8, bcEAN_13, bcInterleaved2of5 : + begin + Result := Length(Characters); + for I := 1 to Result do + bcDigits[I] := StrToInt(Characters[I]); + end; + bcCodabar : + begin + Result := Length(Characters); + for I := 1 to Result do begin + case Characters[I] of + '0'..'9' : bcDigits[I] := StrToInt(Characters[I]); + '-' : bcDigits[I] := 10; + '$' : bcDigits[I] := 11; + ':' : bcDigits[I] := 12; + '/' : bcDigits[I] := 13; + '.' : bcDigits[I] := 14; + '+' : bcDigits[I] := 15; + 'A', 'a' : bcDigits[I] := 16; + 'B', 'b' : bcDigits[I] := 17; + 'C', 'c' : bcDigits[I] := 18; + 'D', 'd' : bcDigits[I] := 19; + else + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + end; + bcCode11 : + begin + Result := Length(Characters); + for I := 1 to Result do begin + case Characters[I] of + '0'..'9' : bcDigits[I] := StrToInt(Characters[I]); + '-' : bcDigits[I] := 10; + else + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + end; + bcCode39 : + begin + Result := Length(Characters); + for I := 1 to Result do begin + case Characters[I] of + '0'..'9' : bcDigits[I] := StrToInt(Characters[I]); + 'A'..'Z' : bcDigits[I] := Ord(Characters[I]) - Ord('A') + 10; + '-' : bcDigits[I] := 36; + '.' : bcDigits[I] := 37; + ' ' : bcDigits[I] := 38; + '$' : bcDigits[I] := 39; + '/' : bcDigits[I] := 40; + '+' : bcDigits[I] := 41; + '%' : bcDigits[I] := 42; + '*' : bcDigits[I] := 43; + else + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + end; + bcCode93 : + begin + Result := Length(Characters); + J := 1; + I := 1; + while I <= Result do begin + S := Code93Map[Characters[I]]; + if Length(S) > 1 then begin + case S[1] of + '$' : bcDigits[J] := 43; {(+)} + '%' : bcDigits[J] := 44; {(%)} + '/' : bcDigits[J] := 45; {(/)} + '+' : bcDigits[J] := 46; {(+)} + else + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + Inc(J); + S := S[2]; + end; + + case S[1] of + '0'..'9' : bcDigits[J] := Ord(S[1])-Ord('0'); + 'A'..'Z' : bcDigits[J] := 10 + Ord(S[1])-Ord('A'); + '-' : bcDigits[J] := 36; + '.' : bcDigits[J] := 37; + ' ' : bcDigits[J] := 38; + '$' : bcDigits[J] := 39; + '/' : bcDigits[J] := 40; + '+' : bcDigits[J] := 41; + '%' : bcDigits[J] := 42; + else + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + Inc(I); + Inc(J); + end; + Result := J; + end; + bcCode128 : + Result := GetCode128Digits; + end; +end; + +function TStBarCode.GetVersion : string; +begin + Result := StVersionStr; +end; + +procedure TStBarCode.Loaded; +begin + inherited Loaded; + CalcBarCode; +end; + +procedure TStBarCode.Paint; +var + Margin : Integer; + R : TRect; +begin + {use our font} + Canvas.Font := Font; + + {clear the canvas} + Canvas.Brush.Color := Color; + Canvas.Brush.Style := bsSolid; + Canvas.FillRect(ClientRect); + + {adjust height of rect to provide top and bottom margin} + R := ClientRect; + Margin := RectHeight(R)*10 div 100; + InflateRect(R, 0, -Margin); + PaintPrim(R); +end; + +procedure TStBarCode.PaintPrim(const R : TRect); +begin + Canvas.Brush.Style := bsClear; + Canvas.Brush.Color := FBarColor; + Canvas.Pen.Color := FBarColor; + DrawBarCode(R); +end; + +procedure TStBarCode.PaintToCanvas(ACanvas : TCanvas; ARect : TRect); +var + Margin : Integer; + SavedDC : LongInt; + R : TRect; +begin + Canvas.Handle := ACanvas.Handle; + SavedDC := SaveDC(ACanvas.Handle); + try + {use our font} + Canvas.Font := Font; + + {clear the specified area of the canvas} + Canvas.Brush.Color := Color; + Canvas.Brush.Style := bsSolid; + Canvas.FillRect(ARect); + + {adjust height of rect to provide top and bottom margin} + R := ARect; + Margin := RectHeight(R)*10 div 100; + InflateRect(R, 0, -Margin); + PaintPrim(R); + finally + Canvas.Handle := 0; + RestoreDC(ACanvas.Handle, SavedDC); + end; +end; + +procedure TStBarCode.PaintToCanvasSize(ACanvas : TCanvas; X, Y, H : Double); +var + TH : Integer; + PixelsPerInchX : Integer; + PixelsPerInchY : Integer; + OldPPI : Integer; + SavedDC : LongInt; + R : TRect; + SmallestWidth : Double; +begin + Canvas.Handle := ACanvas.Handle; + SavedDC := SaveDC(ACanvas.Handle); + try + {get some information about this device context} + PixelsPerInchX := GetDeviceCaps(Canvas.Handle, LOGPIXELSX); + PixelsPerInchY := GetDeviceCaps(Canvas.Handle, LOGPIXELSY); + + OldPPI := Canvas.Font.PixelsPerInch; + {this is necessary because of a Delphi buglet} + Canvas.Font.PixelsPerInch := PixelsPerInchY; + + {use our font} + Canvas.Font := Font; + + {determine narrowest line width} + SmallestWidth := SmallestLineWidth(PixelsPerInchX); + + {find sizes for the BarCode elements} + bcBarModWidth := Round(FBarWidth/1000 * PixelsPerInchX); + if bcBarModWidth < FBarToSpaceRatio then + bcBarModWidth := Round(FBarToSpaceRatio); + if bcBarModWidth < SmallestWidth then + bcBarModWidth := Round(SmallestWidth); + bcSpaceModWidth := Round(bcBarModWidth / FBarToSpaceRatio); + CalcBarCodeWidth; + + {convert to a rect} + R := Rect(Round(X * PixelsPerInchX), + Round(Y * PixelsPerInchY), + Round(X * PixelsPerInchX) + bcNormalWidth + bcSpaceWidth + bcSupplementWidth, + Round((Y + H) * PixelsPerInchY)); + + {increase height of rect to allow for text} + if FShowCode and (Code > '') then begin + TH :=Canvas.TextHeight(Code); + Inc(R.Bottom, TH + (TH div 4)); + end; + + PaintPrim(R); + Canvas.Font.PixelsPerInch := OldPPI; + Invalidate; + finally + Canvas.Handle := 0; + RestoreDC(ACanvas.Handle, SavedDC); + end; +end; + +procedure TStBarCode.PaintToDC(DC : hDC; ARect : TRect); +var + Margin : Integer; + SavedDC : LongInt; + R : TRect; +begin + Canvas.Handle := DC; + SavedDC := SaveDC(DC); + try + {use our font} + Canvas.Font := Font; + + {clear the specified area of the canvas} + Canvas.Brush.Color := Color; + Canvas.Brush.Style := bsSolid; + Canvas.FillRect(ARect); + + {adjust height of rect to provide top and bottom margin} + R := ARect; + Margin := RectHeight(R)*10 div 100; + InflateRect(R, 0, -Margin); + PaintPrim(R); + finally + Canvas.Handle := 0; + RestoreDC(DC, SavedDC); + end; +end; + +procedure TStBarCode.PaintToDCSize(DC : hDC; X, Y, W, H : Double); +begin + Canvas.Handle := DC; + PaintToCanvasSize(Canvas, X, Y, H); +end; + +procedure TStBarCode.SaveToFile(const FileName : string); +var + Bitmap : TBitmap; +begin + Bitmap := TBitmap.Create; + try + Bitmap.Width := ClientWidth; + Bitmap.Height := ClientHeight; + PaintToDC(Bitmap.Canvas.Handle, ClientRect); + Bitmap.SaveToFile(FileName); + finally + Bitmap.Free; + end +end; + +procedure TStBarCode.SetAddCheckChar(Value : Boolean); +begin + if Value <> FAddCheckChar then begin + FAddCheckChar := Value; + CalcBarCode; + Invalidate; + end; +end; + +procedure TStBarCode.SetBarCodeType(Value : TStBarCodeType); +begin + if Value <> FBarCodeType then begin + FBarCodeType := Value; + CalcBarCode; + Invalidate; + end; +end; + +procedure TStBarCode.SetBarColor(Value : TColor); +begin + if Value <> FBarColor then begin + FBarColor := Value; + Invalidate; + end; +end; + +procedure TStBarCode.SetBarToSpaceRatio(Value : Double); +begin + {always uses a bar to space ratio of 1} + if FBarCodeType in [bcInterleaved2of5, bcCode11, bcCode39, bcCode93, bcCode128] then + Value := 1; + + if Value <> FBarToSpaceRatio then begin + FBarToSpaceRatio := Value; + CalcBarCode; + Invalidate; + end; +end; + +procedure TStBarCode.SetBarNarrowToWideRatio(Value : Integer); +begin + if Value <> FBarNarrowToWideRatio then begin + FBarNarrowToWideRatio := Value; + CalcBarCode; + Invalidate; + end; +end; + +procedure TStBarCode.SetBarWidth(Value : Double); +begin + if Value <> FBarWidth then begin + FBarWidth := Value; + Invalidate; + end; +end; + +procedure TStBarCode.SetBearerBars(Value : Boolean); +begin + if Value <> FBearerBars then begin + FBearerBars := Value; + Invalidate; + end; +end; + +procedure TStBarCode.SetCode(const AValue : string); +begin + if FBarCodeType in [bcCode39] then + FCode := UpperCase(AValue) + else if FBarCodeType in [bcCodabar] then + FCode := LowerCase(AValue) + else + FCode := AValue; + CalcBarCode; + Invalidate; +end; + +procedure TStBarCode.SetCode128Subset(Value : TStCode128CodeSubset); +begin + if Value <> FCode128Subset then begin + FCode128Subset := Value; + CalcBarCode; + Invalidate; + end; +end; + +procedure TStBarCode.SetExtendedSyntax (const v : Boolean); +begin + if v <> FExtendedSyntax then begin + FExtendedSyntax := v; + CalcBarCode; + Invalidate; + end; +end; + +procedure TStBarCode.SetShowCode(Value : Boolean); +begin + if Value <> FShowCode then begin + FShowCode := Value; + Invalidate; + end; +end; + +procedure TStBarCode.SetShowGuardChars(Value : Boolean); +begin + if Value <> FShowGuardChars then begin + FShowGuardChars := Value; + Invalidate; + end; +end; + +procedure TStBarCode.SetSupplementalCode(const Value : string); +begin + if Value <> FSupplementalCode then begin + FSupplementalCode := Value; + CalcBarCode; + Invalidate; + end; +end; + +procedure TStBarCode.SetTallGuardBars(Value : Boolean); +begin + if Value <> FTallGuardBars then begin + FTallGuardBars := Value; + Invalidate; + end; +end; + +procedure TStBarCode.SetVersion(const Value : string); +begin +end; + +function TStBarCode.SmallestLineWidth(PixelsPerInch : Integer) : Double; +begin + Result := PixelsPerInch * 0.010; {10 mils} + if Result < 1 then + Result := 1; +end; + +function TStBarCode.Validate(DisplayError : Boolean) : Boolean; +var + I : Integer; + CheckC : Integer; + CheckK : Integer; +begin + Result := True; + try + case FBarCodeType of + bcUPC_A : + begin + {11 or 12 characters} + if not (Length(Code) in [11, 12]) then + RaiseStError(EStBarCodeError, stscInvalidUPCACodeLen); + try + GetDigits(Code); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + + GetCheckCharacters(Code, CheckC, CheckK); + if (Length(Code) = 12) and (CheckC <> bcDigits[12]) then + RaiseStError(EStBarCodeError, stscInvalidCheckCharacter); + end; + bcUPC_E : + begin + {6 characters} + if not (Length(Code) = 6) then + RaiseStError(EStBarCodeError, stscInvalidUPCACodeLen); + try + GetDigits(Code); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + bcEAN_8 : + begin + {7 or 8 characters} + if not (Length(Code) in [7, 8]) then + RaiseStError(EStBarCodeError, stscInvalidEAN8CodeLen); + try + GetDigits(Code); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + + GetCheckCharacters(Code, CheckC, CheckK); + if (Length(Code) = 8) and (CheckC <> bcDigits[8]) then + RaiseStError(EStBarCodeError, stscInvalidCheckCharacter); + end; + bcEAN_13 : + begin + {12 or 13 characters} + if not (Length(Code) in [12, 13]) then + RaiseStError(EStBarCodeError, stscInvalidEAN13CodeLen); + try + GetDigits(Code); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + + GetCheckCharacters(Code, CheckC, CheckK); + if (Length(Code) = 13) and (CheckC <> bcDigits[13]) then + RaiseStError(EStBarCodeError, stscInvalidCheckCharacter); + end; + bcInterleaved2of5 : + begin + try + GetDigits(Code); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + bcCodabar : + begin + for I := 1 to Length(Code) do + if not (Code[I] in ['0'..'9', '-', '$', ':', '/', '.', '+', 'a'..'d', 'A'..'D']) then + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + bcCode11 : + begin + for I := 1 to Length(Code) do + if not (Code[I] in ['0'..'9', '-']) then + RaiseStError(EStBarCodeError, stscInvalidCharacter); + {test check characters} + if not FAddCheckChar then begin + GetCheckCharacters(Code, CheckC, CheckK); + if (StrToInt(Code[Length(Code)-1]) <> CheckC) or + (StrToInt(Code[Length(Code)]) <> CheckK) then + RaiseStError(EStBarCodeError, stscInvalidCheckCharacter); + end; + end; + bcCode39 : + begin + for I := 1 to Length(Code) do + if not (Code[I] in ['0'..'9', 'A'..'Z', 'a'..'z', + '-', '.', ' ', '$', '/', '+', '%', '*']) then + RaiseStError(EStBarCodeError, stscInvalidCharacter); + {check for embedded guard character} + for I := 2 to Length(Code)-1 do + if Code[I] = '*' then + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + bcCode93 : + begin + try + GetCheckCharacters(Code, CheckC, CheckK); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + bcCode128 : + begin + try + GetCheckCharacters(Code, CheckC, CheckK); + except + RaiseStError(EStBarCodeError, stscInvalidCharacter); + end; + end; + end; + {check supplemental code} + if FSupplementalCode > '' then + if not (Length(FSupplementalCode) in [2, 5]) then + RaiseStError(EStBarCodeError, stscInvalidSupCodeLen); + except + Result := False; + if DisplayError then + raise; + end; +end; + + +end. diff --git a/components/systools/source/run/stbarpn.pas b/components/systools/source/run/stbarpn.pas new file mode 100644 index 000000000..a77f83587 --- /dev/null +++ b/components/systools/source/run/stbarpn.pas @@ -0,0 +1,649 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StBarPN.pas 4.04 *} +{*********************************************************} +{* SysTools: PostNet Bar Code component *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +unit StBarPN; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, + {$ELSE} + Windows, Messages, + {$ENDIF} + Classes, ClipBrd, Controls, Graphics, SysUtils, + StBase, StConst, StStrL; + +type + TStPNBarCodeDims = packed record + PixPerBar : Longint; + PixPerSpace : Longint; + ShortBarHeight : Longint; + TallBarHeight : Longint; + Width : Longint; + Height : Longint; + end; + + TStPNBarCodeRes = packed record + XRes : Longint; + YRes : Longint; + end; + + TStPNBarCode = class(TGraphicControl) + protected {private} + {property variables} + FPostalCode : string; + FCheckNumber : Integer; + + + {internal variables} + pnbcDisplayDims : TStPNBarCodeDims; + pnbcDefRes : TStPNBarCodeRes; + + {property methods} + function GetVersion : string; + procedure SetPostalCode(Value : String); + procedure SetVersion (const v : string); + + {internal methods} + function DrawTallBar(C : TCanvas; + Dims : TStPNBarCodeDims; + XPos : Integer; + AddSpace : Boolean) : Longint; + function DrawShortBar(C : TCanvas; + Dims : TStPNBarCodeDims; + XPos : Integer; + AddSpace : Boolean) : Longint; + function DrawNumber(C : TCanvas; + Dims : TStPNBarCodeDims; + Value : Integer; + XPos : Longint; + FrontGuard : Boolean; + EndGuard : Boolean) : Longint; + procedure DrawBarCode(C : TCanvas; Dims : TStPNBarCodeDims); + procedure SetCheckNumber; + +(* + procedure CMTextChanged(var Msg : TMessage); + message CM_TEXTCHANGED; +*) + + protected + procedure Loaded; override; + procedure Paint; override; + public + constructor Create(AOwner : TComponent); override; + + procedure ComputeSizes(C : TCanvas; + Res : TStPNBarCodeRes; + var Dims : TStPNBarCodeDims); + procedure CopyToClipboard; + procedure PaintToCanvas(ACanvas : TCanvas; Position : TPoint); + procedure PaintToDC(DC : hDC; Position : TPoint); + procedure PaintToPrinterCanvas(ACanvas : TCanvas; Position : TPoint); + procedure PaintToPrinterDC(DC : hDC; Position : TPoint); + procedure SaveToFile(ACanvas : TCanvas; const FileName : string); + procedure SaveToFileRes(Res : TStPNBarCodeRes; const FileName : string); + + published + {properties} + property Cursor; + property Enabled; + property Hint; + property ParentShowHint; + property ShowHint; + property Visible; + + property PostalCode : string read FPostalCode write SetPostalCode; + + property Version : string read GetVersion write SetVersion stored False; + + {events} + property OnClick; + property OnDblClick; + property OnMouseDown; + property OnMouseMove; + property OnMouseUp; + end; + + +implementation + +{$IFDEF FPC} +uses + Dialogs; +{$ENDIF} + +{*** TStPNBarCode ***} + +function TStPNBarCode.GetVersion : string; +begin + Result := StVersionStr; +end; + + +procedure TStPNBarCode.SetVersion(const v : string); +begin +end; + +constructor TStPNBarCode.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + {defaults} + pnbcDefRes.XRes := 0; + pnbcDefRes.YRes := 0; +{set arbitrary values for height/width so that component automatically resizes} + Height := 10; + Width := 10; + PostalCode := '12345'; + SetCheckNumber; +end; + + +procedure TStPNBarCode.Loaded; +begin + inherited Loaded; + Invalidate; +end; + + +procedure TStPNBarCode.Paint; +begin + ComputeSizes(Canvas, pnbcDefRes, pnbcDisplayDims); + Height := pnbcDisplayDims.Height; + Width := pnbcDisplayDims.Width; + DrawBarCode(Canvas, pnbcDisplayDims); +end; + + +procedure TStPNBarCode.SetCheckNumber; +var + I : Longint; +begin + if (Length(TrimL(FPostalCode)) < 5) then Exit; + FCheckNumber := 0; + for I := 1 to Length(FPostalCode) do + FCheckNumber := FCheckNumber + StrToInt(FPostalCode[I]); + I := FCheckNumber mod 10; + if (I > 0) then + FCheckNumber := 10 - I + else + FCheckNumber := 0; +end; + +procedure TStPNBarCode.SetPostalCode(Value : string); +var + I : Integer; + Local : string; +begin + if (csLoading in ComponentState) then Exit; + + Local := TrimL(Value); + + {strip non-numerics} + I := 1; + repeat + if not (Local[I] in ['0'..'9']) then + System.Delete(Local, I, 1) + else + Inc(I); + until (I > Length(Local)); + + { looks like a valid Postal Code?} + if (Local <> FPostalCode) then begin + if (Length(Local) in [5, 9, 11]) then begin + FPostalCode := Local; + SetCheckNumber; + Invalidate; + end else + RaiseStError(EStPNBarCodeError, stscInvalidLength); + end; { else it's the same code, don't bother updating } +end; + + +function TStPNBarCode.DrawTallBar(C : TCanvas; + Dims : TStPNBarCodeDims; + XPos : Integer; + AddSpace : Boolean) : Longint; +var + YPos : Longint; +begin + Result := XPos; + YPos := Dims.Height - 5 - Dims.TallBarHeight; + C.Rectangle(XPos, YPos, XPos+Dims.PixPerBar, YPos+Dims.TallBarHeight); + Result := Result + Dims.PixPerBar; + + if (AddSpace) then + Inc(Result, Dims.PixPerSpace); +end; + + +function TStPNBarCode.DrawShortBar(C : TCanvas; + Dims : TStPNBarCodeDims; + XPos : Integer; + AddSpace : Boolean) : Longint; +var + YPos : Longint; +begin + Result := XPos; + YPos := Dims.Height - 5 - Dims.ShortBarHeight; + C.Rectangle(XPos, YPos, XPos+Dims.PixPerBar, YPos+Dims.ShortBarHeight); + Result := Result + Dims.PixPerBar; + + if (AddSpace) then + Inc(Result, Dims.PixPerSpace); +end; + + +function TStPNBarCode.DrawNumber(C : TCanvas; + Dims : TStPNBarCodeDims; + Value : Integer; + XPos : Longint; + FrontGuard : Boolean; + EndGuard : Boolean) : Longint; +begin + Result := XPos; + if (FrontGuard) then + Result := DrawTallBar(C, Dims, Result, True); + + case Value of + 0 : begin + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + end; + + 1 : begin + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + end; + + 2 : begin + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + end; + + 3 : begin + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + end; + + 4 : begin + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + end; + + 5 : begin + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + end; + + 6 : begin + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + end; + + 7 : begin + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + end; + + 8 : begin + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + end; + + 9 : begin + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawTallBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + Result := DrawShortBar(C, Dims, Result, True); + end; + end; + + if (EndGuard) then + Result := DrawTallBar(C, Dims, Result, False); +end; + + +procedure TStPNBarCode.ComputeSizes(C : TCanvas; + Res : TStPNBarCodeRes; + var Dims : TStPNBarCodeDims); +var + PPIX, + PPIY : Longint; +begin + if csLoading in ComponentState then + Exit; + {get resolution} + if ((Res.XRes > 0) and (Res.YRes > 0)) then begin + PPIX := Res.XRes; + PPIY := Res.YRes; + end else begin + PPIX := GetDeviceCaps(C.Handle, LOGPIXELSX); + PPIY := GetDeviceCaps(C.Handle, LOGPIXELSY); + end; + + {PN bar is 0.015" to 0.025" - use mid value} + {add 1 since Canvas.Rectangle draws 1 pixel less than Width} + Dims.PixPerBar := Round(PPIX * 0.017) + 1; + + {CenterLine distance is 0.0416" to 0.0500". Space is that minus width of bar} + {In all cases the Pitch must be 22 +/-2 bars/Inch where a bar is the bar and} + {the trailing space} + + {add 1 since Canvas.Rectangle draws 1 pixel less than Width} + Dims.PixPerSpace := Round(0.0475 * PPIX) - Dims.PixPerBar + 1; + + {max height of short bar is 0.050" +/-0.010". To allow for 75dpi, go a} + {little less} + {add 1 since Canvas.Rectangle draws 1 pixel less than Height} + Dims.ShortBarHeight := Round(0.047 * PPIY) + 1; + + {max height of tall bar is 0.125" +/-0.010". To allow for 75dpi, go a} + {little less} + {add 1 since Canvas.Rectangle draws 1 pixel less than Height} + Dims.TallBarHeight := Round(0.122 * PPIY) + 1; + + + {Total Width of Canvas = + FrontGuardBar + Space + + (NumberChars + CheckChar) * (5 * (PixelsPerBar + PixelsPerSpace)) + + (EndBar w/o Space) + + 5 pixels left/right margin + } + Dims.Width := + (Dims.PixPerBar + Dims.PixPerSpace) + + (Length(PostalCode) + 1) * (5 * (Dims.PixPerBar + Dims.PixPerSpace)) + + Dims.PixPerBar + 10; + + {Height = Height of tall bar + 3 pixel top/bottom margin} + Dims.Height := Dims.TallBarHeight + 3; +end; + + +procedure TStPNBarCode.DrawBarCode(C : TCanvas; Dims : TStPNBarCodeDims); +var + I, + XPos : Longint; +begin + if csLoading in ComponentState then + Exit; + + C.Brush.Color := clBlack; + C.Brush.Style := bsSolid; + + {Draw the Code} + XPos := 5; + XPos := DrawNumber(C, Dims, StrToInt(PostalCode[1]), XPos, True, False); + for I := 2 to Length(PostalCode) do + XPos := DrawNumber(C, Dims, StrToInt(PostalCode[I]), XPos, False, False); + DrawNumber(C, Dims, FCheckNumber, XPos, False, True); +end; + + +(* +procedure TStPNBarCode.CMTextChanged(var Msg : TMessage); +begin + SetCheckNumber; + Invalidate; +end; +*) + +procedure TStPNBarCode.CopyToClipboard; +var + {$IFNDEF FPC} + MetaFile : TMetaFile; + MetaFileCanvas : TMetaFileCanvas; + {$ENDIF} + Bitmap : TBitmap; + Dims : TStPNBarCodeDims; +begin + Clipboard.Clear; + Clipboard.Open; + try + {bitmap} + Bitmap := TBitmap.Create; + try + ComputeSizes(Bitmap.Canvas, pnbcDefRes, Dims); + Bitmap.Width := Dims.Width; + Bitmap.Height := Dims.Height; + DrawBarCode(Bitmap.Canvas, Dims); + Clipboard.Assign(Bitmap); + + {$IFNDEF FPC} + {metafile} + MetaFile := TMetaFile.Create; + try + MetaFileCanvas := TMetaFileCanvas.Create(MetaFile, 0); + try + MetaFile.Enhanced := True; + MetaFile.Width := ClientWidth; + MetaFile.Height := ClientHeight; + MetaFileCanvas.Draw(0, 0, Bitmap); + finally + MetaFileCanvas.Free; + end; + Clipboard.Assign(MetaFile); + finally + MetaFile.Free; + end; + {$ENDIF} + + finally + Bitmap.Free; + end + finally + Clipboard.Close; + end; +end; + + + +procedure TStPNBarCode.PaintToDC(DC : hDC; Position : TPoint); +var + Bmp : TBitmap; + ACanvas : TCanvas; + Dims : TStPNBarCodeDims; + R1, + R2 : TRect; +begin + ACanvas := TCanvas.Create; + ACanvas.Handle := DC; + Bmp := TBitmap.Create; + try + ComputeSizes(ACanvas, pnbcDefRes, Dims); + Bmp.Height := Dims.Height; + Bmp.Width := Dims.Width; + R1 := Rect(0, 0, Dims.Width, Dims.Height); + R2 := Rect(Position.X, Position.Y, + Dims.Width + Position.X, + Dims.Height + Position.Y); + + DrawBarCode(Bmp.Canvas, Dims); + ACanvas.CopyRect(R2, Bmp.Canvas, R1); + finally + Bmp.Free; + ACanvas.Free; + end; +end; + + + +procedure TStPNBarCode.PaintToCanvas(ACanvas : TCanvas; Position : TPoint); +begin + PaintToDC(ACanvas.Handle, Position); +end; + + + +procedure TStPNBarCode.PaintToPrinterCanvas(ACanvas : TCanvas; + Position : TPoint); +begin + PaintToPrinterDC(ACanvas.Handle, Position); +end; + + + +procedure TStPNBarCode.PaintToPrinterDC(DC : hDC; Position : TPoint); +var + Bmp : TBitmap; + ACanvas : TCanvas; + Dims : TStPNBarCodeDims; + R1, + R2 : TRect; + + Info : PBitMapInfo; + InfoSize : DWORD; + ImageSize : DWORD; + Image : Pointer; +begin + {$IFDEF FPC} + // FIX ME + ShowMessage('This function is not yet implemented.'); + {$ELSE} + ACanvas := TCanvas.Create; + Bmp := TBitmap.Create; + ACanvas.Handle := DC; + try + ComputeSizes(ACanvas, pnbcDefRes, Dims); + Bmp.Height := Dims.Height; + Bmp.Width := Dims.Width; + R1 := Rect(0, 0, Dims.Width, Dims.Height); + R2 := Rect(Position.X, Position.Y, + Dims.Width + Position.X, + Dims.Height + Position.Y); + + DrawBarCode(Bmp.Canvas, Dims); + + {Delphi does not allow a simple Canvas.CopyRect to the printer Canvas} + with Bmp do begin + GetDIBSizes(Handle, InfoSize, ImageSize); + GetMem(Info, InfoSize); + try + GetMem(Image, ImageSize); + try + GetDIB(Handle, Palette, Info^, Image^); + with Info^.bmiHeader do begin + StretchDIBits(ACanvas.Handle, + R2.Left, R2.Top, Dims.Width, Dims.Height, + 0, 0, biWidth, biHeight, + Image, Info^, DIB_RGB_COLORS, SRCCOPY); + end; + finally + FreeMem(Image, ImageSize) + end; + finally + FreeMem(Info, InfoSize); + end; + end; + finally + Bmp.Free; + ACanvas.Free; + end; + {$ENDIF} +end; + + + +procedure TStPNBarCode.SaveToFile(ACanvas : TCanvas; + const FileName : string); +var + Bmp : TBitmap; + Dims : TStPNBarCodeDims; +begin + Bmp := TBitmap.Create; + try + ComputeSizes(ACanvas, pnbcDefRes, Dims); + Bmp.Height := Dims.Height; + Bmp.Width := Dims.Width; + DrawBarCode(Bmp.Canvas, Dims); + Bmp.SaveToFile(FileName); + finally + Bmp.Free; + end; +end; + + + +procedure TStPNBarCode.SaveToFileRes(Res : TStPNBarCodeRes; + const FileName : string); +var + Bmp : TBitmap; + Dims : TStPNBarCodeDims; +begin + Bmp := TBitmap.Create; + try + ComputeSizes(Bmp.Canvas, Res, Dims); + Bmp.Height := Dims.Height; + Bmp.Width := Dims.Width; + DrawBarCode(Bmp.Canvas, Dims); + Bmp.SaveToFile(FileName); + finally + Bmp.Free; + end; +end; + +end. diff --git a/components/systools/source/run/stccy.dat b/components/systools/source/run/stccy.dat new file mode 100644 index 000000000..f5a045138 --- /dev/null +++ b/components/systools/source/run/stccy.dat @@ -0,0 +1,315 @@ +; World Currency Information +; ISO 4217-style currency information +; Format: +;[ISOCode] +;ISOName=<ISO 4217 3 Letter Currency ID> +;ISOCode=<ISO 4217 3 Digit Currency Number> +;UnitMajor=<Major Currency Name> +;UnitMinor=<Minor Currency Name> +;Ratio=<ratio of minor currency to major> +;Name=<Country-Currency Name> + +[AUD] +ISOName=AUD +ISOCode=036 +UnitMajor=dollar +UnitMinor=cent +Ratio=100 +Name=Australian Dollar + +[ATS] +ISOName=ATS +ISOCode=040 +UnitMajor=schilling +UnitMinor=groschen +Ratio=100 +Name=Austrian Schilling + +[BEF] +ISOName=BEF +ISOCode=056 +UnitMajor=franc +Ratio=100 +UnitMinor= +Name=Belgium Franc + +[BRL] +ISOName=BRL +ISOCode=986 +UnitMajor=real +UnitMinor=centavo +Ratio=100 +Name=Brazilian Real + +[CAD] +ISOName=CAD +ISOCode=124 +UnitMajor=dollar +UnitMinor=cent +Ratio=100 +Name=Canadian Dollar + +[CNY] +ISOName=CNY +ISOCode=156 +UnitMajor=yuan renminbi +UnitMinor=jiao +Ratio=100 +Name=Chinese Renminbi Yuan + +[DKK] +ISOName=DKK +ISOCode=208 +UnitMajor=krone +UnitMinor=øre +Ratio=100 +Name=Danish Krone + +[DEM] +ISOName=DEM +ISOCode=276 +UnitMajor=deutsche mark +UnitMinor=pfennig +Ratio=100 +Name=Deutsche Mark + +[NLG] +ISOName=NLG +ISOCode=528 +UnitMajor=gulden +UnitMinor=cent +Ratio=100 +Name=Dutch Guilder + +[EGP] +ISOName=EGP +ISOCode=818 +UnitMajor=pound +UnitMinor=piaster +Ratio=100 +Name=Egytian Pound + +[EUR] +ISOName=EUR +ISOCode=978 +UnitMajor=Euro +UnitMinor=euro-cent +Ratio=100 +Name=Euro + +[FRF] +ISOName=FRF +ISOCode=250 +UnitMajor=franc +UnitMinor=centime +Ratio=100 +Name=French Franc + +[GRD] +ISOName=GRD +ISOCode=300 +UnitMajor=drachma +UnitMinor=lepta +Ratio=100 +Name=Greek Drachma + +[HKD] +ISOName=HKD +ISOCode=344 +UnitMajor=dollar +UnitMinor=cent +Ratio=100 +Name=Hong Kong Dollar + +[ISK] +ISOName=ISK +ISOCode=352 +UnitMajor=króna +UnitMinor=aurar +Ratio=100 +Name=Icelandic Króna + +[INR] +ISOName=INR +ISOCode=356 +UnitMajor=rupee +UnitMinor=paise +Ratio=100 +Name=Indian Rupee + +[ILS] +ISOName=ILS +ISOCode=376 +UnitMajor=new shekel +UnitMinor=agorot +Ratio=100 +Name=Israel Shekel + +[ITL] +ISOName=ITL +ISOCode=380 +UnitMajor=lira +UnitMinor=ml +Ratio=100 +Name=Italian Lira + +[JPY] +ISOName=JPY +ISOCode=392 +UnitMajor=yen +UnitMinor=sen +Ratio=100 +Name=Japanese Yen + +[MXN] +ISOName=MXN +ISOCode=484 +UnitMajor=peso +UnitMinor=centavo +Ratio=100 +Name=Mexican Peso + +[NZD] +ISOName=NZD +ISOCode=554 +UnitMajor=dollar +UnitMinor=cent +Ratio=100 +Name=New Zealand Dollar + +[NOK] +ISOName=NOK +ISOCode=578 +UnitMajor=krone +UnitMinor=øre +Ratio=100 +Name=Norwegian Krone + +[PLZ] +ISOName=PLZ +ISOCode=616 +UnitMajor=zloty +UnitMinor=groszy +Ratio=100 +Name=Poland New Zloty + +[PTE] +ISOName=PTE +ISOCode=620 +UnitMajor=escudo +UnitMinor=centavo +Ratio=100 +Name=Portuguese Escudo + +[RUR] +ISOName=RUR +ISOCode=810 +UnitMajor=ruble +UnitMinor=kopeck +Ratio=100 +Name=Russian Federation Rouble + +[SGD] +ISOName=SGD +ISOCode=702 +UnitMajor=dollar +UnitMinor=cent +Ratio=100 +Name=Singapore Dollar + +[ESP] +ISOName=ESP +ISOCode=724 +UnitMajor=peseta +UnitMinor=centimo +Ratio=100 +Name=Spanish Peseta + +[GBP] +ISOName=GBP +ISOCode=826 +UnitMajor=pound +UnitMinor=pence +Ratio=100 +Name=Sterling + +[SEK] +ISOName=SEK +ISOCode=752 +UnitMajor=krona (pl. kronor) +UnitMinor=öre +Ratio=100 +Name=Swedish Krona + +[CHF] +ISOName=CHF +ISOCode=756 +UnitMajor=franc +UnitMinor=rappen +Ratio=100 +Name=Swiss Franc + +[USD] +ISOName=USD +ISOCode=840 +UnitMajor=dollar +UnitMinor=cent +Ratio=100 +Name=US DOLLAR + +[DTR] +ISOName=DTR +ISOCode=005 +UnitMajor=rex +UnitMinor=campi +Ratio=100 +Name=Dinotopia Rex + +[ZQP] +ISOName=ZQP +ISOCode=002 +UnitMajor=pazoor +UnitMinor=dharma +Ratio=100 +Name=Zothique Pazoor + +[LAM] +ISOName=LAM +ISOCode=001 +UnitMajor=minim +UnitMinor=speck +Ratio=100 +Name=Lilliputia Minim + +[BNG] +ISOName=BNG +ISOCode=008 +UnitMajor=gargantua +UnitMinor=bloat +Ratio=100 +Name=Brobdinagian Gargantua + +[ELE] +ISOName=ELE +ISOCode=011 +UnitMajor=elbo +UnitMinor=kni +Ratio=100 +Name=Elbonia Elbo + +[SBD] +ISOName=SBD +ISOCode=333 +UnitMajor=dunge +UnitMinor=slop +Ratio=100 +Name=Slobovia Dunge + +[RYE] +ISOName=RYE +ISOCode=666 +UnitMajor=eldritch +UnitMinor=voor +Ratio=100 +Name=Rlyeh Eldritch + diff --git a/components/systools/source/run/stccycnv.dat b/components/systools/source/run/stccycnv.dat new file mode 100644 index 000000000..5926276c4 --- /dev/null +++ b/components/systools/source/run/stccycnv.dat @@ -0,0 +1,9842 @@ +[ATS:AUD] +source=ATS +target=AUD +intermediate= +rate=1.968585243 +type=mul +date=7980 +[ATS:BEF] +source=ATS +target=BEF +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[ATS:BNG] +source=ATS +target=BNG +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[ATS:BRL] +source=ATS +target=BRL +intermediate= +rate=6.214447921 +type=div +date=7980 +[ATS:CAD] +source=ATS +target=CAD +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[ATS:CHF] +source=ATS +target=CHF +intermediate= +rate=4.558033427 +type=div +date=7980 +[ATS:CNY] +source=ATS +target=CNY +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[ATS:DEM] +source=ATS +target=DEM +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[ATS:DKK] +source=ATS +target=DKK +intermediate= +rate=2.533696115 +type=div +date=7980 +[ATS:DTR] +source=ATS +target=DTR +intermediate= +rate=4.487361637 +type=div +date=7980 +[ATS:EGP] +source=ATS +target=EGP +intermediate= +rate=4.714167443 +type=div +date=7980 +[ATS:ELE] +source=ATS +target=ELE +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[ATS:ESP] +source=ATS +target=ESP +intermediate= +rate=2.573725119 +type=mul +date=7980 +[ATS:EUR] +source=ATS +target=EUR +intermediate= +rate=6.221280535 +type=div +date=7980 +[ATS:FRF] +source=ATS +target=FRF +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[ATS:GBP] +source=ATS +target=GBP +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[ATS:GRD] +source=ATS +target=GRD +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[ATS:HKD] +source=ATS +target=HKD +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[ATS:ILS] +source=ATS +target=ILS +intermediate= +rate=3.300112578 +type=div +date=7980 +[ATS:INR] +source=ATS +target=INR +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[ATS:ISK] +source=ATS +target=ISK +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[ATS:ITL] +source=ATS +target=ITL +intermediate= +rate=1.131448300 +type=mul +date=7980 +[ATS:JPY] +source=ATS +target=JPY +intermediate= +rate=4.043905598 +type=mul +date=7980 +[ATS:LAM] +source=ATS +target=LAM +intermediate= +rate=1.080419265 +type=div +date=7980 +[ATS:MXN] +source=ATS +target=MXN +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[ATS:NLG] +source=ATS +target=NLG +intermediate= +rate=6.973154785 +type=mul +date=7980 +[ATS:NOK] +source=ATS +target=NOK +intermediate= +rate=3.539131289 +type=div +date=7980 +[ATS:NZD] +source=ATS +target=NZD +intermediate= +rate=5.654235414 +type=div +date=7980 +[ATS:PLZ] +source=ATS +target=PLZ +intermediate= +rate=5.568687112 +type=div +date=7980 +[ATS:PTE] +source=ATS +target=PTE +intermediate= +rate=2.408629012 +type=mul +date=7980 +[ATS:RUR] +source=ATS +target=RUR +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[ATS:RYE] +source=ATS +target=RYE +intermediate= +rate=6.244467644 +type=mul +date=7980 +[ATS:SBD] +source=ATS +target=SBD +intermediate= +rate=5.702862623 +type=mul +date=7980 +[ATS:SEK] +source=ATS +target=SEK +intermediate= +rate=5.480264463 +type=mul +date=7980 +[ATS:SGD] +source=ATS +target=SGD +intermediate= +rate=1.685152822 +type=mul +date=7980 +[ATS:USD] +source=ATS +target=USD +intermediate= +rate=6.016300210 +type=div +date=7980 +[ATS:ZQP] +source=ATS +target=ZQP +intermediate= +rate=4.598523155 +type=div +date=7980 +[AUD:ATS] +source=AUD +target=ATS +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[AUD:BEF] +source=AUD +target=BEF +intermediate= +rate=3.999540851 +type=div +date=7980 +[AUD:BNG] +source=AUD +target=BNG +intermediate= +rate=2.082721258 +type=div +date=7980 +[AUD:BRL] +source=AUD +target=BRL +intermediate= +rate=2.480684132 +type=mul +date=7980 +[AUD:CAD] +source=AUD +target=CAD +intermediate= +rate=4.536722449 +type=mul +date=7980 +[AUD:CHF] +source=AUD +target=CHF +intermediate= +rate=5.095703469 +type=div +date=7980 +[AUD:CNY] +source=AUD +target=CNY +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[AUD:DEM] +source=AUD +target=DEM +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[AUD:DKK] +source=AUD +target=DKK +intermediate= +rate=3.318722273 +type=mul +date=7980 +[AUD:DTR] +source=AUD +target=DTR +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[AUD:EGP] +source=AUD +target=EGP +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[AUD:ELE] +source=AUD +target=ELE +intermediate= +rate=2.397803400 +type=div +date=7980 +[AUD:ESP] +source=AUD +target=ESP +intermediate= +rate=6.059376904 +type=mul +date=7980 +[AUD:EUR] +source=AUD +target=EUR +intermediate= +rate=4.289084232 +type=mul +date=7980 +[AUD:FRF] +source=AUD +target=FRF +intermediate= +rate=2.737868601 +type=mul +date=7980 +[AUD:GBP] +source=AUD +target=GBP +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[AUD:GRD] +source=AUD +target=GRD +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[AUD:HKD] +source=AUD +target=HKD +intermediate= +rate=6.827485319 +type=mul +date=7980 +[AUD:ILS] +source=AUD +target=ILS +intermediate= +rate=1.202491301 +type=div +date=7980 +[AUD:INR] +source=AUD +target=INR +intermediate= +rate=2.446087643 +type=div +date=7980 +[AUD:ISK] +source=AUD +target=ISK +intermediate= +rate=2.298573309 +type=mul +date=7980 +[AUD:ITL] +source=AUD +target=ITL +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[AUD:JPY] +source=AUD +target=JPY +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[AUD:LAM] +source=AUD +target=LAM +intermediate= +rate=5.712961964 +type=mul +date=7980 +[AUD:MXN] +source=AUD +target=MXN +intermediate= +rate=6.316404321 +type=mul +date=7980 +[AUD:NLG] +source=AUD +target=NLG +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[AUD:NOK] +source=AUD +target=NOK +intermediate= +rate=3.826845502 +type=div +date=7980 +[AUD:NZD] +source=AUD +target=NZD +intermediate= +rate=4.004650972 +type=mul +date=7980 +[AUD:PLZ] +source=AUD +target=PLZ +intermediate= +rate=1.725258113 +type=div +date=7980 +[AUD:PTE] +source=AUD +target=PTE +intermediate= +rate=5.270489735 +type=div +date=7980 +[AUD:RUR] +source=AUD +target=RUR +intermediate= +rate=5.263091224 +type=mul +date=7980 +[AUD:RYE] +source=AUD +target=RYE +intermediate= +rate=4.771149395 +type=div +date=7980 +[AUD:SBD] +source=AUD +target=SBD +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[AUD:SEK] +source=AUD +target=SEK +intermediate= +rate=1.925905992 +type=div +date=7980 +[AUD:SGD] +source=AUD +target=SGD +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[AUD:USD] +source=AUD +target=USD +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[AUD:ZQP] +source=AUD +target=ZQP +intermediate= +rate=4.718820557 +type=div +date=7980 +[BEF:ATS] +source=BEF +target=ATS +intermediate= +rate=1.795389753 +type=mul +date=7980 +[BEF:AUD] +source=BEF +target=AUD +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[BEF:BNG] +source=BEF +target=BNG +intermediate= +rate=4.830491421 +type=mul +date=7980 +[BEF:BRL] +source=BEF +target=BRL +intermediate= +rate=2.309195914 +type=div +date=7980 +[BEF:CAD] +source=BEF +target=CAD +intermediate= +rate=4.185176421 +type=div +date=7980 +[BEF:CHF] +source=BEF +target=CHF +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[BEF:CNY] +source=BEF +target=CNY +intermediate= +rate=2.643859581 +type=mul +date=7980 +[BEF:DEM] +source=BEF +target=DEM +intermediate= +rate=6.945529788 +type=div +date=7980 +[BEF:DKK] +source=BEF +target=DKK +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[BEF:DTR] +source=BEF +target=DTR +intermediate= +rate=4.567108199 +type=mul +date=7980 +[BEF:EGP] +source=BEF +target=EGP +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[BEF:ELE] +source=BEF +target=ELE +intermediate= +rate=2.487302247 +type=mul +date=7980 +[BEF:ESP] +source=BEF +target=ESP +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[BEF:EUR] +source=BEF +target=EUR +intermediate= +rate=5.396272523 +type=mul +date=7980 +[BEF:FRF] +source=BEF +target=FRF +intermediate= +rate=2.204178282 +type=div +date=7980 +[BEF:GBP] +source=BEF +target=GBP +intermediate= +rate=5.201954165 +type=div +date=7980 +[BEF:GRD] +source=BEF +target=GRD +intermediate= +rate=3.718589120 +type=div +date=7980 +[BEF:HKD] +source=BEF +target=HKD +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[BEF:ILS] +source=BEF +target=ILS +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[BEF:INR] +source=BEF +target=INR +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[BEF:ISK] +source=BEF +target=ISK +intermediate= +rate=4.299821359 +type=mul +date=7980 +[BEF:ITL] +source=BEF +target=ITL +intermediate= +rate=4.184404715 +type=mul +date=7980 +[BEF:JPY] +source=BEF +target=JPY +intermediate= +rate=5.371437388 +type=div +date=7980 +[BEF:LAM] +source=BEF +target=LAM +intermediate= +rate=1.530140996 +type=div +date=7980 +[BEF:MXN] +source=BEF +target=MXN +intermediate= +rate=1.370548344 +type=mul +date=7980 +[BEF:NLG] +source=BEF +target=NLG +intermediate= +rate=5.328016103 +type=div +date=7980 +[BEF:NOK] +source=BEF +target=NOK +intermediate= +rate=2.491043718 +type=mul +date=7980 +[BEF:NZD] +source=BEF +target=NZD +intermediate= +rate=4.280891659 +type=div +date=7980 +[BEF:PLZ] +source=BEF +target=PLZ +intermediate= +rate=5.051810058 +type=mul +date=7980 +[BEF:PTE] +source=BEF +target=PTE +intermediate= +rate=2.335878573 +type=div +date=7980 +[BEF:RUR] +source=BEF +target=RUR +intermediate= +rate=6.770604719 +type=mul +date=7980 +[BEF:RYE] +source=BEF +target=RYE +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[BEF:SBD] +source=BEF +target=SBD +intermediate= +rate=2.506411826 +type=mul +date=7980 +[BEF:SEK] +source=BEF +target=SEK +intermediate= +rate=5.481294714 +type=mul +date=7980 +[BEF:SGD] +source=BEF +target=SGD +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[BEF:USD] +source=BEF +target=USD +intermediate= +rate=2.684821486 +type=mul +date=7980 +[BEF:ZQP] +source=BEF +target=ZQP +intermediate= +rate=5.230057351 +type=mul +date=7980 +[BNG:ATS] +source=BNG +target=ATS +intermediate= +rate=4.092414308 +type=mul +date=7980 +[BNG:AUD] +source=BNG +target=AUD +intermediate= +rate=5.339407902 +type=div +date=7980 +[BNG:BEF] +source=BNG +target=BEF +intermediate= +rate=3.942780570 +type=div +date=7980 +[BNG:BRL] +source=BNG +target=BRL +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[BNG:CAD] +source=BNG +target=CAD +intermediate= +rate=1.057261504 +type=div +date=7980 +[BNG:CHF] +source=BNG +target=CHF +intermediate= +rate=4.379395971 +type=mul +date=7980 +[BNG:CNY] +source=BNG +target=CNY +intermediate= +rate=3.609246353 +type=mul +date=7980 +[BNG:DEM] +source=BNG +target=DEM +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[BNG:DKK] +source=BNG +target=DKK +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[BNG:DTR] +source=BNG +target=DTR +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[BNG:EGP] +source=BNG +target=EGP +intermediate= +rate=6.980847120 +type=div +date=7980 +[BNG:ELE] +source=BNG +target=ELE +intermediate= +rate=1.557476555 +type=div +date=7980 +[BNG:ESP] +source=BNG +target=ESP +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[BNG:EUR] +source=BNG +target=EUR +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[BNG:FRF] +source=BNG +target=FRF +intermediate= +rate=6.605035101 +type=mul +date=7980 +[BNG:GBP] +source=BNG +target=GBP +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[BNG:GRD] +source=BNG +target=GRD +intermediate= +rate=5.977258826 +type=div +date=7980 +[BNG:HKD] +source=BNG +target=HKD +intermediate= +rate=1.294017640 +type=mul +date=7980 +[BNG:ILS] +source=BNG +target=ILS +intermediate= +rate=4.730938224 +type=mul +date=7980 +[BNG:INR] +source=BNG +target=INR +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[BNG:ISK] +source=BNG +target=ISK +intermediate= +rate=5.252370917 +type=mul +date=7980 +[BNG:ITL] +source=BNG +target=ITL +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[BNG:JPY] +source=BNG +target=JPY +intermediate= +rate=4.808060825 +type=mul +date=7980 +[BNG:LAM] +source=BNG +target=LAM +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[BNG:MXN] +source=BNG +target=MXN +intermediate= +rate=2.902609947 +type=mul +date=7980 +[BNG:NLG] +source=BNG +target=NLG +intermediate= +rate=4.569016488 +type=div +date=7980 +[BNG:NOK] +source=BNG +target=NOK +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[BNG:NZD] +source=BNG +target=NZD +intermediate= +rate=4.406225832 +type=div +date=7980 +[BNG:PLZ] +source=BNG +target=PLZ +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[BNG:PTE] +source=BNG +target=PTE +intermediate= +rate=1.808821590 +type=mul +date=7980 +[BNG:RUR] +source=BNG +target=RUR +intermediate= +rate=3.758991400 +type=div +date=7980 +[BNG:RYE] +source=BNG +target=RYE +intermediate= +rate=4.357113294 +type=mul +date=7980 +[BNG:SBD] +source=BNG +target=SBD +intermediate= +rate=4.308555051 +type=div +date=7980 +[BNG:SEK] +source=BNG +target=SEK +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[BNG:SGD] +source=BNG +target=SGD +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[BNG:USD] +source=BNG +target=USD +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[BNG:ZQP] +source=BNG +target=ZQP +intermediate= +rate=1.424738643 +type=div +date=7980 +[BRL:ATS] +source=BRL +target=ATS +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[BRL:AUD] +source=BRL +target=AUD +intermediate= +rate=1.227957213 +type=div +date=7980 +[BRL:BEF] +source=BRL +target=BEF +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[BRL:BNG] +source=BRL +target=BNG +intermediate= +rate=3.275581412 +type=div +date=7980 +[BRL:CAD] +source=BRL +target=CAD +intermediate= +rate=1.251219266 +type=div +date=7980 +[BRL:CHF] +source=BRL +target=CHF +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[BRL:CNY] +source=BRL +target=CNY +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[BRL:DEM] +source=BRL +target=DEM +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[BRL:DKK] +source=BRL +target=DKK +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[BRL:DTR] +source=BRL +target=DTR +intermediate= +rate=1.551967978 +type=div +date=7980 +[BRL:EGP] +source=BRL +target=EGP +intermediate= +rate=5.219059936 +type=div +date=7980 +[BRL:ELE] +source=BRL +target=ELE +intermediate= +rate=1.202306593 +type=mul +date=7980 +[BRL:ESP] +source=BRL +target=ESP +intermediate= +rate=2.756415904 +type=mul +date=7980 +[BRL:EUR] +source=BRL +target=EUR +intermediate= +rate=5.145451919 +type=div +date=7980 +[BRL:FRF] +source=BRL +target=FRF +intermediate= +rate=5.074349887 +type=mul +date=7980 +[BRL:GBP] +source=BRL +target=GBP +intermediate= +rate=2.366799082 +type=mul +date=7980 +[BRL:GRD] +source=BRL +target=GRD +intermediate= +rate=5.056899496 +type=div +date=7980 +[BRL:HKD] +source=BRL +target=HKD +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[BRL:ILS] +source=BRL +target=ILS +intermediate= +rate=2.909756196 +type=div +date=7980 +[BRL:INR] +source=BRL +target=INR +intermediate= +rate=5.662038655 +type=div +date=7980 +[BRL:ISK] +source=BRL +target=ISK +intermediate= +rate=2.202275818 +type=div +date=7980 +[BRL:ITL] +source=BRL +target=ITL +intermediate= +rate=4.145995705 +type=div +date=7980 +[BRL:JPY] +source=BRL +target=JPY +intermediate= +rate=1.534421199 +type=mul +date=7980 +[BRL:LAM] +source=BRL +target=LAM +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[BRL:MXN] +source=BRL +target=MXN +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[BRL:NLG] +source=BRL +target=NLG +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[BRL:NOK] +source=BRL +target=NOK +intermediate= +rate=2.322237863 +type=div +date=7980 +[BRL:NZD] +source=BRL +target=NZD +intermediate= +rate=6.833799537 +type=mul +date=7980 +[BRL:PLZ] +source=BRL +target=PLZ +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[BRL:PTE] +source=BRL +target=PTE +intermediate= +rate=3.228397112 +type=mul +date=7980 +[BRL:RUR] +source=BRL +target=RUR +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[BRL:RYE] +source=BRL +target=RYE +intermediate= +rate=3.866933801 +type=div +date=7980 +[BRL:SBD] +source=BRL +target=SBD +intermediate= +rate=2.411365936 +type=mul +date=7980 +[BRL:SEK] +source=BRL +target=SEK +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[BRL:SGD] +source=BRL +target=SGD +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[BRL:USD] +source=BRL +target=USD +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[BRL:ZQP] +source=BRL +target=ZQP +intermediate= +rate=5.823069106 +type=div +date=7980 +[CAD:ATS] +source=CAD +target=ATS +intermediate= +rate=3.574847030 +type=div +date=7980 +[CAD:AUD] +source=CAD +target=AUD +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[CAD:BEF] +source=CAD +target=BEF +intermediate= +rate=4.083741701 +type=div +date=7980 +[CAD:BNG] +source=CAD +target=BNG +intermediate= +rate=4.176808552 +type=mul +date=7980 +[CAD:BRL] +source=CAD +target=BRL +intermediate= +rate=2.954387320 +type=div +date=7980 +[CAD:CHF] +source=CAD +target=CHF +intermediate= +rate=4.965319465 +type=div +date=7980 +[CAD:CNY] +source=CAD +target=CNY +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[CAD:DEM] +source=CAD +target=DEM +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[CAD:DKK] +source=CAD +target=DKK +intermediate= +rate=4.575262120 +type=div +date=7980 +[CAD:DTR] +source=CAD +target=DTR +intermediate= +rate=5.766912299 +type=mul +date=7980 +[CAD:EGP] +source=CAD +target=EGP +intermediate= +rate=5.964298347 +type=div +date=7980 +[CAD:ELE] +source=CAD +target=ELE +intermediate= +rate=6.240200487 +type=div +date=7980 +[CAD:ESP] +source=CAD +target=ESP +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[CAD:EUR] +source=CAD +target=EUR +intermediate= +rate=1.106000929 +type=mul +date=7980 +[CAD:FRF] +source=CAD +target=FRF +intermediate= +rate=6.298454499 +type=div +date=7980 +[CAD:GBP] +source=CAD +target=GBP +intermediate= +rate=3.225483933 +type=mul +date=7980 +[CAD:GRD] +source=CAD +target=GRD +intermediate= +rate=1.061604976 +type=div +date=7980 +[CAD:HKD] +source=CAD +target=HKD +intermediate= +rate=1.358487074 +type=div +date=7980 +[CAD:ILS] +source=CAD +target=ILS +intermediate= +rate=3.907522145 +type=div +date=7980 +[CAD:INR] +source=CAD +target=INR +intermediate= +rate=2.234972297 +type=mul +date=7980 +[CAD:ISK] +source=CAD +target=ISK +intermediate= +rate=3.723592679 +type=mul +date=7980 +[CAD:ITL] +source=CAD +target=ITL +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[CAD:JPY] +source=CAD +target=JPY +intermediate= +rate=6.083003764 +type=div +date=7980 +[CAD:LAM] +source=CAD +target=LAM +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[CAD:MXN] +source=CAD +target=MXN +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[CAD:NLG] +source=CAD +target=NLG +intermediate= +rate=5.477115783 +type=mul +date=7980 +[CAD:NOK] +source=CAD +target=NOK +intermediate= +rate=5.078843278 +type=div +date=7980 +[CAD:NZD] +source=CAD +target=NZD +intermediate= +rate=6.210511298 +type=mul +date=7980 +[CAD:PLZ] +source=CAD +target=PLZ +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[CAD:PTE] +source=CAD +target=PTE +intermediate= +rate=5.254992308 +type=mul +date=7980 +[CAD:RUR] +source=CAD +target=RUR +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[CAD:RYE] +source=CAD +target=RYE +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[CAD:SBD] +source=CAD +target=SBD +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[CAD:SEK] +source=CAD +target=SEK +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[CAD:SGD] +source=CAD +target=SGD +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[CAD:USD] +source=CAD +target=USD +intermediate= +rate=2.484363863 +type=mul +date=7980 +[CAD:ZQP] +source=CAD +target=ZQP +intermediate= +rate=6.665603084 +type=div +date=7980 +[CHF:ATS] +source=CHF +target=ATS +intermediate= +rate=6.186884614 +type=div +date=7980 +[CHF:AUD] +source=CHF +target=AUD +intermediate= +rate=3.731584937 +type=mul +date=7980 +[CHF:BEF] +source=CHF +target=BEF +intermediate= +rate=6.773359777 +type=div +date=7980 +[CHF:BNG] +source=CHF +target=BNG +intermediate= +rate=2.049983142 +type=mul +date=7980 +[CHF:BRL] +source=CHF +target=BRL +intermediate= +rate=2.692146690 +type=div +date=7980 +[CHF:CAD] +source=CHF +target=CAD +intermediate= +rate=3.042827131 +type=mul +date=7980 +[CHF:CNY] +source=CHF +target=CNY +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[CHF:DEM] +source=CHF +target=DEM +intermediate= +rate=6.296915679 +type=div +date=7980 +[CHF:DKK] +source=CHF +target=DKK +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[CHF:DTR] +source=CHF +target=DTR +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[CHF:EGP] +source=CHF +target=EGP +intermediate= +rate=4.049594624 +type=div +date=7980 +[CHF:ELE] +source=CHF +target=ELE +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[CHF:ESP] +source=CHF +target=ESP +intermediate= +rate=6.984649997 +type=div +date=7980 +[CHF:EUR] +source=CHF +target=EUR +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[CHF:FRF] +source=CHF +target=FRF +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[CHF:GBP] +source=CHF +target=GBP +intermediate= +rate=4.312071987 +type=div +date=7980 +[CHF:GRD] +source=CHF +target=GRD +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[CHF:HKD] +source=CHF +target=HKD +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[CHF:ILS] +source=CHF +target=ILS +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[CHF:INR] +source=CHF +target=INR +intermediate= +rate=5.259343157 +type=div +date=7980 +[CHF:ISK] +source=CHF +target=ISK +intermediate= +rate=6.712702730 +type=div +date=7980 +[CHF:ITL] +source=CHF +target=ITL +intermediate= +rate=1.721603122 +type=mul +date=7980 +[CHF:JPY] +source=CHF +target=JPY +intermediate= +rate=3.213242962 +type=mul +date=7980 +[CHF:LAM] +source=CHF +target=LAM +intermediate= +rate=1.825664458 +type=mul +date=7980 +[CHF:MXN] +source=CHF +target=MXN +intermediate= +rate=2.706813900 +type=div +date=7980 +[CHF:NLG] +source=CHF +target=NLG +intermediate= +rate=5.729139460 +type=mul +date=7980 +[CHF:NOK] +source=CHF +target=NOK +intermediate= +rate=6.844638990 +type=mul +date=7980 +[CHF:NZD] +source=CHF +target=NZD +intermediate= +rate=4.565693784 +type=mul +date=7980 +[CHF:PLZ] +source=CHF +target=PLZ +intermediate= +rate=4.162552652 +type=div +date=7980 +[CHF:PTE] +source=CHF +target=PTE +intermediate= +rate=3.515686058 +type=div +date=7980 +[CHF:RUR] +source=CHF +target=RUR +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[CHF:RYE] +source=CHF +target=RYE +intermediate= +rate=3.698684300 +type=mul +date=7980 +[CHF:SBD] +source=CHF +target=SBD +intermediate= +rate=2.970985153 +type=mul +date=7980 +[CHF:SEK] +source=CHF +target=SEK +intermediate= +rate=4.059376050 +type=mul +date=7980 +[CHF:SGD] +source=CHF +target=SGD +intermediate= +rate=4.965790187 +type=mul +date=7980 +[CHF:USD] +source=CHF +target=USD +intermediate= +rate=2.038461298 +type=mul +date=7980 +[CHF:ZQP] +source=CHF +target=ZQP +intermediate= +rate=1.578134590 +type=mul +date=7980 +[CNY:ATS] +source=CNY +target=ATS +intermediate= +rate=5.887259487 +type=mul +date=7980 +[CNY:AUD] +source=CNY +target=AUD +intermediate= +rate=4.484509167 +type=div +date=7980 +[CNY:BEF] +source=CNY +target=BEF +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[CNY:BNG] +source=CNY +target=BNG +intermediate= +rate=5.691924951 +type=div +date=7980 +[CNY:BRL] +source=CNY +target=BRL +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[CNY:CAD] +source=CNY +target=CAD +intermediate= +rate=6.277012270 +type=div +date=7980 +[CNY:CHF] +source=CNY +target=CHF +intermediate= +rate=4.368206830 +type=div +date=7980 +[CNY:DEM] +source=CNY +target=DEM +intermediate= +rate=5.956844611 +type=mul +date=7980 +[CNY:DKK] +source=CNY +target=DKK +intermediate= +rate=1.161336530 +type=div +date=7980 +[CNY:DTR] +source=CNY +target=DTR +intermediate= +rate=2.751780453 +type=div +date=7980 +[CNY:EGP] +source=CNY +target=EGP +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[CNY:ELE] +source=CNY +target=ELE +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[CNY:ESP] +source=CNY +target=ESP +intermediate= +rate=1.199391242 +type=div +date=7980 +[CNY:EUR] +source=CNY +target=EUR +intermediate= +rate=4.674604879 +type=div +date=7980 +[CNY:FRF] +source=CNY +target=FRF +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[CNY:GBP] +source=CNY +target=GBP +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[CNY:GRD] +source=CNY +target=GRD +intermediate= +rate=4.011580475 +type=div +date=7980 +[CNY:HKD] +source=CNY +target=HKD +intermediate= +rate=4.917833064 +type=mul +date=7980 +[CNY:ILS] +source=CNY +target=ILS +intermediate= +rate=4.614460033 +type=mul +date=7980 +[CNY:INR] +source=CNY +target=INR +intermediate= +rate=3.863675775 +type=div +date=7980 +[CNY:ISK] +source=CNY +target=ISK +intermediate= +rate=4.367518158 +type=mul +date=7980 +[CNY:ITL] +source=CNY +target=ITL +intermediate= +rate=6.108808655 +type=div +date=7980 +[CNY:JPY] +source=CNY +target=JPY +intermediate= +rate=6.019017573 +type=div +date=7980 +[CNY:LAM] +source=CNY +target=LAM +intermediate= +rate=6.982172795 +type=div +date=7980 +[CNY:MXN] +source=CNY +target=MXN +intermediate= +rate=1.584567481 +type=mul +date=7980 +[CNY:NLG] +source=CNY +target=NLG +intermediate= +rate=5.777763292 +type=div +date=7980 +[CNY:NOK] +source=CNY +target=NOK +intermediate= +rate=3.949814952 +type=mul +date=7980 +[CNY:NZD] +source=CNY +target=NZD +intermediate= +rate=3.851723808 +type=mul +date=7980 +[CNY:PLZ] +source=CNY +target=PLZ +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[CNY:PTE] +source=CNY +target=PTE +intermediate= +rate=6.359883798 +type=mul +date=7980 +[CNY:RUR] +source=CNY +target=RUR +intermediate= +rate=5.886357419 +type=div +date=7980 +[CNY:RYE] +source=CNY +target=RYE +intermediate= +rate=5.496459383 +type=div +date=7980 +[CNY:SBD] +source=CNY +target=SBD +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[CNY:SEK] +source=CNY +target=SEK +intermediate= +rate=6.278432969 +type=div +date=7980 +[CNY:SGD] +source=CNY +target=SGD +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[CNY:USD] +source=CNY +target=USD +intermediate= +rate=4.584846903 +type=div +date=7980 +[CNY:ZQP] +source=CNY +target=ZQP +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[DEM:ATS] +source=DEM +target=ATS +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[DEM:AUD] +source=DEM +target=AUD +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[DEM:BEF] +source=DEM +target=BEF +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[DEM:BNG] +source=DEM +target=BNG +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[DEM:BRL] +source=DEM +target=BRL +intermediate= +rate=2.328627010 +type=mul +date=7980 +[DEM:CAD] +source=DEM +target=CAD +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[DEM:CHF] +source=DEM +target=CHF +intermediate= +rate=3.594294374 +type=mul +date=7980 +[DEM:CNY] +source=DEM +target=CNY +intermediate= +rate=5.541504497 +type=div +date=7980 +[DEM:DKK] +source=DEM +target=DKK +intermediate= +rate=4.780773227 +type=mul +date=7980 +[DEM:DTR] +source=DEM +target=DTR +intermediate= +rate=4.369120035 +type=div +date=7980 +[DEM:EGP] +source=DEM +target=EGP +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[DEM:ELE] +source=DEM +target=ELE +intermediate= +rate=3.553643336 +type=mul +date=7980 +[DEM:ESP] +source=DEM +target=ESP +intermediate= +rate=5.469241085 +type=mul +date=7980 +[DEM:EUR] +source=DEM +target=EUR +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[DEM:FRF] +source=DEM +target=FRF +intermediate= +rate=6.039141785 +type=div +date=7980 +[DEM:GBP] +source=DEM +target=GBP +intermediate= +rate=4.493668522 +type=mul +date=7980 +[DEM:GRD] +source=DEM +target=GRD +intermediate= +rate=2.713581759 +type=div +date=7980 +[DEM:HKD] +source=DEM +target=HKD +intermediate= +rate=5.071921123 +type=div +date=7980 +[DEM:ILS] +source=DEM +target=ILS +intermediate= +rate=5.834685410 +type=div +date=7980 +[DEM:INR] +source=DEM +target=INR +intermediate= +rate=1.820736222 +type=mul +date=7980 +[DEM:ISK] +source=DEM +target=ISK +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[DEM:ITL] +source=DEM +target=ITL +intermediate= +rate=3.742760384 +type=mul +date=7980 +[DEM:JPY] +source=DEM +target=JPY +intermediate= +rate=4.362871582 +type=mul +date=7980 +[DEM:LAM] +source=DEM +target=LAM +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[DEM:MXN] +source=DEM +target=MXN +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[DEM:NLG] +source=DEM +target=NLG +intermediate= +rate=4.646498036 +type=mul +date=7980 +[DEM:NOK] +source=DEM +target=NOK +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[DEM:NZD] +source=DEM +target=NZD +intermediate= +rate=5.106194733 +type=mul +date=7980 +[DEM:PLZ] +source=DEM +target=PLZ +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[DEM:PTE] +source=DEM +target=PTE +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[DEM:RUR] +source=DEM +target=RUR +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[DEM:RYE] +source=DEM +target=RYE +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[DEM:SBD] +source=DEM +target=SBD +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[DEM:SEK] +source=DEM +target=SEK +intermediate= +rate=6.967162601 +type=div +date=7980 +[DEM:SGD] +source=DEM +target=SGD +intermediate= +rate=6.067108335 +type=mul +date=7980 +[DEM:USD] +source=DEM +target=USD +intermediate= +rate=5.370097055 +type=mul +date=7980 +[DEM:ZQP] +source=DEM +target=ZQP +intermediate= +rate=2.260239836 +type=mul +date=7980 +[DKK:ATS] +source=DKK +target=ATS +intermediate= +rate=4.396664397 +type=mul +date=7980 +[DKK:AUD] +source=DKK +target=AUD +intermediate= +rate=3.933646339 +type=mul +date=7980 +[DKK:BEF] +source=DKK +target=BEF +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[DKK:BNG] +source=DKK +target=BNG +intermediate= +rate=2.640846310 +type=mul +date=7980 +[DKK:BRL] +source=DKK +target=BRL +intermediate= +rate=1.687372084 +type=mul +date=7980 +[DKK:CAD] +source=DKK +target=CAD +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[DKK:CHF] +source=DKK +target=CHF +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[DKK:CNY] +source=DKK +target=CNY +intermediate= +rate=4.001110098 +type=mul +date=7980 +[DKK:DEM] +source=DKK +target=DEM +intermediate= +rate=6.226952765 +type=mul +date=7980 +[DKK:DTR] +source=DKK +target=DTR +intermediate= +rate=5.067544504 +type=mul +date=7980 +[DKK:EGP] +source=DKK +target=EGP +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[DKK:ELE] +source=DKK +target=ELE +intermediate= +rate=5.164035304 +type=mul +date=7980 +[DKK:ESP] +source=DKK +target=ESP +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[DKK:EUR] +source=DKK +target=EUR +intermediate= +rate=2.893397411 +type=mul +date=7980 +[DKK:FRF] +source=DKK +target=FRF +intermediate= +rate=6.099092836 +type=mul +date=7980 +[DKK:GBP] +source=DKK +target=GBP +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[DKK:GRD] +source=DKK +target=GRD +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[DKK:HKD] +source=DKK +target=HKD +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[DKK:ILS] +source=DKK +target=ILS +intermediate= +rate=3.940177422 +type=mul +date=7980 +[DKK:INR] +source=DKK +target=INR +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[DKK:ISK] +source=DKK +target=ISK +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[DKK:ITL] +source=DKK +target=ITL +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[DKK:JPY] +source=DKK +target=JPY +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[DKK:LAM] +source=DKK +target=LAM +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[DKK:MXN] +source=DKK +target=MXN +intermediate= +rate=2.567083292 +type=div +date=7980 +[DKK:NLG] +source=DKK +target=NLG +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[DKK:NOK] +source=DKK +target=NOK +intermediate= +rate=6.637822601 +type=mul +date=7980 +[DKK:NZD] +source=DKK +target=NZD +intermediate= +rate=4.731096743 +type=div +date=7980 +[DKK:PLZ] +source=DKK +target=PLZ +intermediate= +rate=4.255943926 +type=mul +date=7980 +[DKK:PTE] +source=DKK +target=PTE +intermediate= +rate=6.138011914 +type=div +date=7980 +[DKK:RUR] +source=DKK +target=RUR +intermediate= +rate=4.458079329 +type=div +date=7980 +[DKK:RYE] +source=DKK +target=RYE +intermediate= +rate=1.177074083 +type=mul +date=7980 +[DKK:SBD] +source=DKK +target=SBD +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[DKK:SEK] +source=DKK +target=SEK +intermediate= +rate=2.220214134 +type=div +date=7980 +[DKK:SGD] +source=DKK +target=SGD +intermediate= +rate=1.635567079 +type=div +date=7980 +[DKK:USD] +source=DKK +target=USD +intermediate= +rate=1.694585718 +type=div +date=7980 +[DKK:ZQP] +source=DKK +target=ZQP +intermediate= +rate=4.259326395 +type=div +date=7980 +[DTR:ATS] +source=DTR +target=ATS +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[DTR:AUD] +source=DTR +target=AUD +intermediate= +rate=3.251602147 +type=div +date=7980 +[DTR:BEF] +source=DTR +target=BEF +intermediate= +rate=2.502155549 +type=mul +date=7980 +[DTR:BNG] +source=DTR +target=BNG +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[DTR:BRL] +source=DTR +target=BRL +intermediate= +rate=3.092293463 +type=mul +date=7980 +[DTR:CAD] +source=DTR +target=CAD +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[DTR:CHF] +source=DTR +target=CHF +intermediate= +rate=4.655602528 +type=div +date=7980 +[DTR:CNY] +source=DTR +target=CNY +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[DTR:DEM] +source=DTR +target=DEM +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[DTR:DKK] +source=DTR +target=DKK +intermediate= +rate=2.414924507 +type=div +date=7980 +[DTR:EGP] +source=DTR +target=EGP +intermediate= +rate=1.887450543 +type=mul +date=7980 +[DTR:ELE] +source=DTR +target=ELE +intermediate= +rate=4.948087807 +type=div +date=7980 +[DTR:ESP] +source=DTR +target=ESP +intermediate= +rate=6.532656113 +type=div +date=7980 +[DTR:EUR] +source=DTR +target=EUR +intermediate= +rate=4.410088065 +type=mul +date=7980 +[DTR:FRF] +source=DTR +target=FRF +intermediate= +rate=4.886392594 +type=mul +date=7980 +[DTR:GBP] +source=DTR +target=GBP +intermediate= +rate=5.183152749 +type=mul +date=7980 +[DTR:GRD] +source=DTR +target=GRD +intermediate= +rate=1.723854794 +type=mul +date=7980 +[DTR:HKD] +source=DTR +target=HKD +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[DTR:ILS] +source=DTR +target=ILS +intermediate= +rate=5.954997486 +type=mul +date=7980 +[DTR:INR] +source=DTR +target=INR +intermediate= +rate=4.880491542 +type=mul +date=7980 +[DTR:ISK] +source=DTR +target=ISK +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[DTR:ITL] +source=DTR +target=ITL +intermediate= +rate=5.244180709 +type=mul +date=7980 +[DTR:JPY] +source=DTR +target=JPY +intermediate= +rate=4.287630888 +type=div +date=7980 +[DTR:LAM] +source=DTR +target=LAM +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[DTR:MXN] +source=DTR +target=MXN +intermediate= +rate=3.358658911 +type=mul +date=7980 +[DTR:NLG] +source=DTR +target=NLG +intermediate= +rate=3.747553470 +type=mul +date=7980 +[DTR:NOK] +source=DTR +target=NOK +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[DTR:NZD] +source=DTR +target=NZD +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[DTR:PLZ] +source=DTR +target=PLZ +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[DTR:PTE] +source=DTR +target=PTE +intermediate= +rate=5.087626701 +type=div +date=7980 +[DTR:RUR] +source=DTR +target=RUR +intermediate= +rate=1.880103129 +type=div +date=7980 +[DTR:RYE] +source=DTR +target=RYE +intermediate= +rate=6.505301367 +type=mul +date=7980 +[DTR:SBD] +source=DTR +target=SBD +intermediate= +rate=3.507532177 +type=div +date=7980 +[DTR:SEK] +source=DTR +target=SEK +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[DTR:SGD] +source=DTR +target=SGD +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[DTR:USD] +source=DTR +target=USD +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[DTR:ZQP] +source=DTR +target=ZQP +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[EGP:ATS] +source=EGP +target=ATS +intermediate= +rate=5.428588762 +type=div +date=7980 +[EGP:AUD] +source=EGP +target=AUD +intermediate= +rate=1.370032811 +type=div +date=7980 +[EGP:BEF] +source=EGP +target=BEF +intermediate= +rate=3.670572745 +type=div +date=7980 +[EGP:BNG] +source=EGP +target=BNG +intermediate= +rate=6.832530010 +type=div +date=7980 +[EGP:BRL] +source=EGP +target=BRL +intermediate= +rate=4.702863018 +type=mul +date=7980 +[EGP:CAD] +source=EGP +target=CAD +intermediate= +rate=1.697432882 +type=div +date=7980 +[EGP:CHF] +source=EGP +target=CHF +intermediate= +rate=3.564200955 +type=mul +date=7980 +[EGP:CNY] +source=EGP +target=CNY +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[EGP:DEM] +source=EGP +target=DEM +intermediate= +rate=5.398138363 +type=mul +date=7980 +[EGP:DKK] +source=EGP +target=DKK +intermediate= +rate=6.155608756 +type=mul +date=7980 +[EGP:DTR] +source=EGP +target=DTR +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[EGP:ELE] +source=EGP +target=ELE +intermediate= +rate=4.456120577 +type=mul +date=7980 +[EGP:ESP] +source=EGP +target=ESP +intermediate= +rate=5.930064606 +type=mul +date=7980 +[EGP:EUR] +source=EGP +target=EUR +intermediate= +rate=3.677374340 +type=mul +date=7980 +[EGP:FRF] +source=EGP +target=FRF +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[EGP:GBP] +source=EGP +target=GBP +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[EGP:GRD] +source=EGP +target=GRD +intermediate= +rate=2.906980242 +type=mul +date=7980 +[EGP:HKD] +source=EGP +target=HKD +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[EGP:ILS] +source=EGP +target=ILS +intermediate= +rate=6.523740723 +type=div +date=7980 +[EGP:INR] +source=EGP +target=INR +intermediate= +rate=3.016388052 +type=div +date=7980 +[EGP:ISK] +source=EGP +target=ISK +intermediate= +rate=1.121954886 +type=div +date=7980 +[EGP:ITL] +source=EGP +target=ITL +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[EGP:JPY] +source=EGP +target=JPY +intermediate= +rate=5.731780724 +type=div +date=7980 +[EGP:LAM] +source=EGP +target=LAM +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[EGP:MXN] +source=EGP +target=MXN +intermediate= +rate=4.215106355 +type=div +date=7980 +[EGP:NLG] +source=EGP +target=NLG +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[EGP:NOK] +source=EGP +target=NOK +intermediate= +rate=1.220470973 +type=mul +date=7980 +[EGP:NZD] +source=EGP +target=NZD +intermediate= +rate=4.518270863 +type=div +date=7980 +[EGP:PLZ] +source=EGP +target=PLZ +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[EGP:PTE] +source=EGP +target=PTE +intermediate= +rate=6.357929888 +type=mul +date=7980 +[EGP:RUR] +source=EGP +target=RUR +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[EGP:RYE] +source=EGP +target=RYE +intermediate= +rate=6.453365943 +type=mul +date=7980 +[EGP:SBD] +source=EGP +target=SBD +intermediate= +rate=6.314500663 +type=mul +date=7980 +[EGP:SEK] +source=EGP +target=SEK +intermediate= +rate=1.864383952 +type=div +date=7980 +[EGP:SGD] +source=EGP +target=SGD +intermediate= +rate=4.914469049 +type=mul +date=7980 +[EGP:USD] +source=EGP +target=USD +intermediate= +rate=1.898108260 +type=div +date=7980 +[EGP:ZQP] +source=EGP +target=ZQP +intermediate= +rate=6.997536342 +type=mul +date=7980 +[ELE:ATS] +source=ELE +target=ATS +intermediate= +rate=4.737169538 +type=div +date=7980 +[ELE:AUD] +source=ELE +target=AUD +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[ELE:BEF] +source=ELE +target=BEF +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[ELE:BNG] +source=ELE +target=BNG +intermediate= +rate=1.457552599 +type=mul +date=7980 +[ELE:BRL] +source=ELE +target=BRL +intermediate= +rate=3.188200534 +type=div +date=7980 +[ELE:CAD] +source=ELE +target=CAD +intermediate= +rate=6.621049709 +type=mul +date=7980 +[ELE:CHF] +source=ELE +target=CHF +intermediate= +rate=2.532750304 +type=mul +date=7980 +[ELE:CNY] +source=ELE +target=CNY +intermediate= +rate=5.708432684 +type=div +date=7980 +[ELE:DEM] +source=ELE +target=DEM +intermediate= +rate=4.083889807 +type=div +date=7980 +[ELE:DKK] +source=ELE +target=DKK +intermediate= +rate=6.557261824 +type=mul +date=7980 +[ELE:DTR] +source=ELE +target=DTR +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[ELE:EGP] +source=ELE +target=EGP +intermediate= +rate=3.722339693 +type=mul +date=7980 +[ELE:ESP] +source=ELE +target=ESP +intermediate= +rate=3.620836862 +type=div +date=7980 +[ELE:EUR] +source=ELE +target=EUR +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[ELE:FRF] +source=ELE +target=FRF +intermediate= +rate=6.470553451 +type=div +date=7980 +[ELE:GBP] +source=ELE +target=GBP +intermediate= +rate=1.377047282 +type=div +date=7980 +[ELE:GRD] +source=ELE +target=GRD +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[ELE:HKD] +source=ELE +target=HKD +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[ELE:ILS] +source=ELE +target=ILS +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[ELE:INR] +source=ELE +target=INR +intermediate= +rate=2.409288421 +type=mul +date=7980 +[ELE:ISK] +source=ELE +target=ISK +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[ELE:ITL] +source=ELE +target=ITL +intermediate= +rate=3.220500327 +type=div +date=7980 +[ELE:JPY] +source=ELE +target=JPY +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[ELE:LAM] +source=ELE +target=LAM +intermediate= +rate=5.401830749 +type=div +date=7980 +[ELE:MXN] +source=ELE +target=MXN +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[ELE:NLG] +source=ELE +target=NLG +intermediate= +rate=3.158175172 +type=mul +date=7980 +[ELE:NOK] +source=ELE +target=NOK +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[ELE:NZD] +source=ELE +target=NZD +intermediate= +rate=2.223062746 +type=div +date=7980 +[ELE:PLZ] +source=ELE +target=PLZ +intermediate= +rate=6.259897298 +type=mul +date=7980 +[ELE:PTE] +source=ELE +target=PTE +intermediate= +rate=3.208922913 +type=mul +date=7980 +[ELE:RUR] +source=ELE +target=RUR +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[ELE:RYE] +source=ELE +target=RYE +intermediate= +rate=1.646689719 +type=mul +date=7980 +[ELE:SBD] +source=ELE +target=SBD +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[ELE:SEK] +source=ELE +target=SEK +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[ELE:SGD] +source=ELE +target=SGD +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[ELE:USD] +source=ELE +target=USD +intermediate= +rate=3.362427690 +type=mul +date=7980 +[ELE:ZQP] +source=ELE +target=ZQP +intermediate= +rate=2.562140313 +type=div +date=7980 +[ESP:ATS] +source=ESP +target=ATS +intermediate= +rate=4.294031656 +type=mul +date=7980 +[ESP:AUD] +source=ESP +target=AUD +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[ESP:BEF] +source=ESP +target=BEF +intermediate= +rate=4.218603323 +type=mul +date=7980 +[ESP:BNG] +source=ESP +target=BNG +intermediate= +rate=3.616382689 +type=div +date=7980 +[ESP:BRL] +source=ESP +target=BRL +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[ESP:CAD] +source=ESP +target=CAD +intermediate= +rate=3.970879186 +type=mul +date=7980 +[ESP:CHF] +source=ESP +target=CHF +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[ESP:CNY] +source=ESP +target=CNY +intermediate= +rate=1.050629443 +type=mul +date=7980 +[ESP:DEM] +source=ESP +target=DEM +intermediate= +rate=3.185931577 +type=mul +date=7980 +[ESP:DKK] +source=ESP +target=DKK +intermediate= +rate=3.738629630 +type=div +date=7980 +[ESP:DTR] +source=ESP +target=DTR +intermediate= +rate=6.457478768 +type=div +date=7980 +[ESP:EGP] +source=ESP +target=EGP +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[ESP:ELE] +source=ESP +target=ELE +intermediate= +rate=4.084901961 +type=div +date=7980 +[ESP:EUR] +source=ESP +target=EUR +intermediate= +rate=5.940949290 +type=mul +date=7980 +[ESP:FRF] +source=ESP +target=FRF +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[ESP:GBP] +source=ESP +target=GBP +intermediate= +rate=6.853431438 +type=div +date=7980 +[ESP:GRD] +source=ESP +target=GRD +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[ESP:HKD] +source=ESP +target=HKD +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[ESP:ILS] +source=ESP +target=ILS +intermediate= +rate=4.826594811 +type=mul +date=7980 +[ESP:INR] +source=ESP +target=INR +intermediate= +rate=2.548837486 +type=mul +date=7980 +[ESP:ISK] +source=ESP +target=ISK +intermediate= +rate=2.461707142 +type=mul +date=7980 +[ESP:ITL] +source=ESP +target=ITL +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[ESP:JPY] +source=ESP +target=JPY +intermediate= +rate=6.773880368 +type=div +date=7980 +[ESP:LAM] +source=ESP +target=LAM +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[ESP:MXN] +source=ESP +target=MXN +intermediate= +rate=2.444928468 +type=div +date=7980 +[ESP:NLG] +source=ESP +target=NLG +intermediate= +rate=2.976334147 +type=mul +date=7980 +[ESP:NOK] +source=ESP +target=NOK +intermediate= +rate=4.712369737 +type=mul +date=7980 +[ESP:NZD] +source=ESP +target=NZD +intermediate= +rate=4.175738081 +type=div +date=7980 +[ESP:PLZ] +source=ESP +target=PLZ +intermediate= +rate=2.425833348 +type=mul +date=7980 +[ESP:PTE] +source=ESP +target=PTE +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[ESP:RUR] +source=ESP +target=RUR +intermediate= +rate=6.455477386 +type=div +date=7980 +[ESP:RYE] +source=ESP +target=RYE +intermediate= +rate=6.372229140 +type=div +date=7980 +[ESP:SBD] +source=ESP +target=SBD +intermediate= +rate=5.481606384 +type=div +date=7980 +[ESP:SEK] +source=ESP +target=SEK +intermediate= +rate=1.515266554 +type=div +date=7980 +[ESP:SGD] +source=ESP +target=SGD +intermediate= +rate=5.910669554 +type=mul +date=7980 +[ESP:USD] +source=ESP +target=USD +intermediate= +rate=1.952009510 +type=mul +date=7980 +[ESP:ZQP] +source=ESP +target=ZQP +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[EUR:ATS] +source=EUR +target=ATS +intermediate= +rate=3.539715215 +type=div +date=7980 +[EUR:AUD] +source=EUR +target=AUD +intermediate= +rate=1.691615248 +type=mul +date=7980 +[EUR:BEF] +source=EUR +target=BEF +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[EUR:BNG] +source=EUR +target=BNG +intermediate= +rate=5.054631765 +type=mul +date=7980 +[EUR:BRL] +source=EUR +target=BRL +intermediate= +rate=6.475637367 +type=div +date=7980 +[EUR:CAD] +source=EUR +target=CAD +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[EUR:CHF] +source=EUR +target=CHF +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[EUR:CNY] +source=EUR +target=CNY +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[EUR:DEM] +source=EUR +target=DEM +intermediate= +rate=1.771637084 +type=mul +date=7980 +[EUR:DKK] +source=EUR +target=DKK +intermediate= +rate=6.400556448 +type=div +date=7980 +[EUR:DTR] +source=EUR +target=DTR +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[EUR:EGP] +source=EUR +target=EGP +intermediate= +rate=4.503855309 +type=div +date=7980 +[EUR:ELE] +source=EUR +target=ELE +intermediate= +rate=6.518244320 +type=mul +date=7980 +[EUR:ESP] +source=EUR +target=ESP +intermediate= +rate=6.052448541 +type=div +date=7980 +[EUR:FRF] +source=EUR +target=FRF +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[EUR:GBP] +source=EUR +target=GBP +intermediate= +rate=4.672287161 +type=div +date=7980 +[EUR:GRD] +source=EUR +target=GRD +intermediate= +rate=6.455976518 +type=div +date=7980 +[EUR:HKD] +source=EUR +target=HKD +intermediate= +rate=5.531475625 +type=mul +date=7980 +[EUR:ILS] +source=EUR +target=ILS +intermediate= +rate=2.467180868 +type=mul +date=7980 +[EUR:INR] +source=EUR +target=INR +intermediate= +rate=3.925961292 +type=div +date=7980 +[EUR:ISK] +source=EUR +target=ISK +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[EUR:ITL] +source=EUR +target=ITL +intermediate= +rate=5.975977218 +type=div +date=7980 +[EUR:JPY] +source=EUR +target=JPY +intermediate= +rate=4.746758024 +type=div +date=7980 +[EUR:LAM] +source=EUR +target=LAM +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[EUR:MXN] +source=EUR +target=MXN +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[EUR:NLG] +source=EUR +target=NLG +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[EUR:NOK] +source=EUR +target=NOK +intermediate= +rate=3.292507632 +type=div +date=7980 +[EUR:NZD] +source=EUR +target=NZD +intermediate= +rate=2.493039514 +type=mul +date=7980 +[EUR:PLZ] +source=EUR +target=PLZ +intermediate= +rate=1.993496465 +type=div +date=7980 +[EUR:PTE] +source=EUR +target=PTE +intermediate= +rate=3.601602074 +type=mul +date=7980 +[EUR:RUR] +source=EUR +target=RUR +intermediate= +rate=2.295646760 +type=mul +date=7980 +[EUR:RYE] +source=EUR +target=RYE +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[EUR:SBD] +source=EUR +target=SBD +intermediate= +rate=1.358985575 +type=div +date=7980 +[EUR:SEK] +source=EUR +target=SEK +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[EUR:SGD] +source=EUR +target=SGD +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[EUR:USD] +source=EUR +target=USD +intermediate= +rate=3.422751699 +type=div +date=7980 +[EUR:ZQP] +source=EUR +target=ZQP +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[FRF:ATS] +source=FRF +target=ATS +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[FRF:AUD] +source=FRF +target=AUD +intermediate= +rate=5.703951121 +type=mul +date=7980 +[FRF:BEF] +source=FRF +target=BEF +intermediate= +rate=5.111180004 +type=mul +date=7980 +[FRF:BNG] +source=FRF +target=BNG +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[FRF:BRL] +source=FRF +target=BRL +intermediate= +rate=5.368664493 +type=div +date=7980 +[FRF:CAD] +source=FRF +target=CAD +intermediate= +rate=4.341500663 +type=mul +date=7980 +[FRF:CHF] +source=FRF +target=CHF +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[FRF:CNY] +source=FRF +target=CNY +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[FRF:DEM] +source=FRF +target=DEM +intermediate= +rate=6.842399736 +type=mul +date=7980 +[FRF:DKK] +source=FRF +target=DKK +intermediate= +rate=6.936494357 +type=mul +date=7980 +[FRF:DTR] +source=FRF +target=DTR +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[FRF:EGP] +source=FRF +target=EGP +intermediate= +rate=6.952825767 +type=mul +date=7980 +[FRF:ELE] +source=FRF +target=ELE +intermediate= +rate=6.382485932 +type=mul +date=7980 +[FRF:ESP] +source=FRF +target=ESP +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[FRF:EUR] +source=FRF +target=EUR +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[FRF:GBP] +source=FRF +target=GBP +intermediate= +rate=1.234761892 +type=div +date=7980 +[FRF:GRD] +source=FRF +target=GRD +intermediate= +rate=4.283198342 +type=div +date=7980 +[FRF:HKD] +source=FRF +target=HKD +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[FRF:ILS] +source=FRF +target=ILS +intermediate= +rate=6.429935966 +type=mul +date=7980 +[FRF:INR] +source=FRF +target=INR +intermediate= +rate=5.684782022 +type=div +date=7980 +[FRF:ISK] +source=FRF +target=ISK +intermediate= +rate=1.151222672 +type=mul +date=7980 +[FRF:ITL] +source=FRF +target=ITL +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[FRF:JPY] +source=FRF +target=JPY +intermediate= +rate=4.888758088 +type=div +date=7980 +[FRF:LAM] +source=FRF +target=LAM +intermediate= +rate=6.473583533 +type=div +date=7980 +[FRF:MXN] +source=FRF +target=MXN +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[FRF:NLG] +source=FRF +target=NLG +intermediate= +rate=1.206513565 +type=mul +date=7980 +[FRF:NOK] +source=FRF +target=NOK +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[FRF:NZD] +source=FRF +target=NZD +intermediate= +rate=1.066534965 +type=div +date=7980 +[FRF:PLZ] +source=FRF +target=PLZ +intermediate= +rate=4.455850559 +type=div +date=7980 +[FRF:PTE] +source=FRF +target=PTE +intermediate= +rate=1.844572282 +type=div +date=7980 +[FRF:RUR] +source=FRF +target=RUR +intermediate= +rate=2.801502884 +type=div +date=7980 +[FRF:RYE] +source=FRF +target=RYE +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[FRF:SBD] +source=FRF +target=SBD +intermediate= +rate=5.694842783 +type=div +date=7980 +[FRF:SEK] +source=FRF +target=SEK +intermediate= +rate=4.277678896 +type=div +date=7980 +[FRF:SGD] +source=FRF +target=SGD +intermediate= +rate=2.386597467 +type=div +date=7980 +[FRF:USD] +source=FRF +target=USD +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[FRF:ZQP] +source=FRF +target=ZQP +intermediate= +rate=2.176219243 +type=div +date=7980 +[GBP:ATS] +source=GBP +target=ATS +intermediate= +rate=2.612514757 +type=mul +date=7980 +[GBP:AUD] +source=GBP +target=AUD +intermediate= +rate=6.704636840 +type=div +date=7980 +[GBP:BEF] +source=GBP +target=BEF +intermediate= +rate=2.218809162 +type=div +date=7980 +[GBP:BNG] +source=GBP +target=BNG +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[GBP:BRL] +source=GBP +target=BRL +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[GBP:CAD] +source=GBP +target=CAD +intermediate= +rate=6.644451222 +type=mul +date=7980 +[GBP:CHF] +source=GBP +target=CHF +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[GBP:CNY] +source=GBP +target=CNY +intermediate= +rate=5.788370207 +type=mul +date=7980 +[GBP:DEM] +source=GBP +target=DEM +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[GBP:DKK] +source=GBP +target=DKK +intermediate= +rate=1.431594498 +type=mul +date=7980 +[GBP:DTR] +source=GBP +target=DTR +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[GBP:EGP] +source=GBP +target=EGP +intermediate= +rate=2.714217301 +type=mul +date=7980 +[GBP:ELE] +source=GBP +target=ELE +intermediate= +rate=6.403349980 +type=mul +date=7980 +[GBP:ESP] +source=GBP +target=ESP +intermediate= +rate=3.885461286 +type=div +date=7980 +[GBP:EUR] +source=GBP +target=EUR +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[GBP:FRF] +source=GBP +target=FRF +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[GBP:GRD] +source=GBP +target=GRD +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[GBP:HKD] +source=GBP +target=HKD +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[GBP:ILS] +source=GBP +target=ILS +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[GBP:INR] +source=GBP +target=INR +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[GBP:ISK] +source=GBP +target=ISK +intermediate= +rate=2.802848739 +type=mul +date=7980 +[GBP:ITL] +source=GBP +target=ITL +intermediate= +rate=2.920446553 +type=mul +date=7980 +[GBP:JPY] +source=GBP +target=JPY +intermediate= +rate=2.912295470 +type=div +date=7980 +[GBP:LAM] +source=GBP +target=LAM +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[GBP:MXN] +source=GBP +target=MXN +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[GBP:NLG] +source=GBP +target=NLG +intermediate= +rate=2.666747733 +type=div +date=7980 +[GBP:NOK] +source=GBP +target=NOK +intermediate= +rate=4.316864621 +type=div +date=7980 +[GBP:NZD] +source=GBP +target=NZD +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[GBP:PLZ] +source=GBP +target=PLZ +intermediate= +rate=3.905795106 +type=div +date=7980 +[GBP:PTE] +source=GBP +target=PTE +intermediate= +rate=4.738660872 +type=mul +date=7980 +[GBP:RUR] +source=GBP +target=RUR +intermediate= +rate=3.708318493 +type=div +date=7980 +[GBP:RYE] +source=GBP +target=RYE +intermediate= +rate=3.371098610 +type=div +date=7980 +[GBP:SBD] +source=GBP +target=SBD +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[GBP:SEK] +source=GBP +target=SEK +intermediate= +rate=2.470863061 +type=div +date=7980 +[GBP:SGD] +source=GBP +target=SGD +intermediate= +rate=5.256808451 +type=div +date=7980 +[GBP:USD] +source=GBP +target=USD +intermediate= +rate=6.682301495 +type=div +date=7980 +[GBP:ZQP] +source=GBP +target=ZQP +intermediate= +rate=4.378934972 +type=div +date=7980 +[GRD:ATS] +source=GRD +target=ATS +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[GRD:AUD] +source=GRD +target=AUD +intermediate= +rate=6.292041450 +type=div +date=7980 +[GRD:BEF] +source=GRD +target=BEF +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[GRD:BNG] +source=GRD +target=BNG +intermediate= +rate=4.400919896 +type=div +date=7980 +[GRD:BRL] +source=GRD +target=BRL +intermediate= +rate=6.371961643 +type=div +date=7980 +[GRD:CAD] +source=GRD +target=CAD +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[GRD:CHF] +source=GRD +target=CHF +intermediate= +rate=4.780204077 +type=div +date=7980 +[GRD:CNY] +source=GRD +target=CNY +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[GRD:DEM] +source=GRD +target=DEM +intermediate= +rate=1.285714854 +type=div +date=7980 +[GRD:DKK] +source=GRD +target=DKK +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[GRD:DTR] +source=GRD +target=DTR +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[GRD:EGP] +source=GRD +target=EGP +intermediate= +rate=4.135506352 +type=div +date=7980 +[GRD:ELE] +source=GRD +target=ELE +intermediate= +rate=2.489042499 +type=mul +date=7980 +[GRD:ESP] +source=GRD +target=ESP +intermediate= +rate=2.912245722 +type=div +date=7980 +[GRD:EUR] +source=GRD +target=EUR +intermediate= +rate=4.882495353 +type=mul +date=7980 +[GRD:FRF] +source=GRD +target=FRF +intermediate= +rate=4.810020488 +type=div +date=7980 +[GRD:GBP] +source=GRD +target=GBP +intermediate= +rate=3.132711029 +type=div +date=7980 +[GRD:HKD] +source=GRD +target=HKD +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[GRD:ILS] +source=GRD +target=ILS +intermediate= +rate=2.230666513 +type=div +date=7980 +[GRD:INR] +source=GRD +target=INR +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[GRD:ISK] +source=GRD +target=ISK +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[GRD:ITL] +source=GRD +target=ITL +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[GRD:JPY] +source=GRD +target=JPY +intermediate= +rate=2.395685523 +type=div +date=7980 +[GRD:LAM] +source=GRD +target=LAM +intermediate= +rate=5.555766519 +type=mul +date=7980 +[GRD:MXN] +source=GRD +target=MXN +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[GRD:NLG] +source=GRD +target=NLG +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[GRD:NOK] +source=GRD +target=NOK +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[GRD:NZD] +source=GRD +target=NZD +intermediate= +rate=5.250319873 +type=mul +date=7980 +[GRD:PLZ] +source=GRD +target=PLZ +intermediate= +rate=1.594420853 +type=div +date=7980 +[GRD:PTE] +source=GRD +target=PTE +intermediate= +rate=2.554004671 +type=div +date=7980 +[GRD:RUR] +source=GRD +target=RUR +intermediate= +rate=1.854036903 +type=div +date=7980 +[GRD:RYE] +source=GRD +target=RYE +intermediate= +rate=3.424541664 +type=div +date=7980 +[GRD:SBD] +source=GRD +target=SBD +intermediate= +rate=3.628919260 +type=mul +date=7980 +[GRD:SEK] +source=GRD +target=SEK +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[GRD:SGD] +source=GRD +target=SGD +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[GRD:USD] +source=GRD +target=USD +intermediate= +rate=1.818986993 +type=div +date=7980 +[GRD:ZQP] +source=GRD +target=ZQP +intermediate= +rate=6.290413989 +type=mul +date=7980 +[HKD:ATS] +source=HKD +target=ATS +intermediate= +rate=3.293404787 +type=div +date=7980 +[HKD:AUD] +source=HKD +target=AUD +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[HKD:BEF] +source=HKD +target=BEF +intermediate= +rate=4.379910829 +type=div +date=7980 +[HKD:BNG] +source=HKD +target=BNG +intermediate= +rate=6.600034135 +type=mul +date=7980 +[HKD:BRL] +source=HKD +target=BRL +intermediate= +rate=3.970268771 +type=mul +date=7980 +[HKD:CAD] +source=HKD +target=CAD +intermediate= +rate=5.740347943 +type=div +date=7980 +[HKD:CHF] +source=HKD +target=CHF +intermediate= +rate=4.295582343 +type=mul +date=7980 +[HKD:CNY] +source=HKD +target=CNY +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[HKD:DEM] +source=HKD +target=DEM +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[HKD:DKK] +source=HKD +target=DKK +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[HKD:DTR] +source=HKD +target=DTR +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[HKD:EGP] +source=HKD +target=EGP +intermediate= +rate=3.300310434 +type=div +date=7980 +[HKD:ELE] +source=HKD +target=ELE +intermediate= +rate=6.371548858 +type=mul +date=7980 +[HKD:ESP] +source=HKD +target=ESP +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[HKD:EUR] +source=HKD +target=EUR +intermediate= +rate=6.687404953 +type=mul +date=7980 +[HKD:FRF] +source=HKD +target=FRF +intermediate= +rate=6.417492951 +type=div +date=7980 +[HKD:GBP] +source=HKD +target=GBP +intermediate= +rate=1.181133610 +type=mul +date=7980 +[HKD:GRD] +source=HKD +target=GRD +intermediate= +rate=4.721755286 +type=mul +date=7980 +[HKD:ILS] +source=HKD +target=ILS +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[HKD:INR] +source=HKD +target=INR +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[HKD:ISK] +source=HKD +target=ISK +intermediate= +rate=4.078881827 +type=mul +date=7980 +[HKD:ITL] +source=HKD +target=ITL +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[HKD:JPY] +source=HKD +target=JPY +intermediate= +rate=3.503860985 +type=div +date=7980 +[HKD:LAM] +source=HKD +target=LAM +intermediate= +rate=6.194236238 +type=div +date=7980 +[HKD:MXN] +source=HKD +target=MXN +intermediate= +rate=3.763949763 +type=mul +date=7980 +[HKD:NLG] +source=HKD +target=NLG +intermediate= +rate=5.801886706 +type=div +date=7980 +[HKD:NOK] +source=HKD +target=NOK +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[HKD:NZD] +source=HKD +target=NZD +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[HKD:PLZ] +source=HKD +target=PLZ +intermediate= +rate=5.567499612 +type=mul +date=7980 +[HKD:PTE] +source=HKD +target=PTE +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[HKD:RUR] +source=HKD +target=RUR +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[HKD:RYE] +source=HKD +target=RYE +intermediate= +rate=5.456574205 +type=mul +date=7980 +[HKD:SBD] +source=HKD +target=SBD +intermediate= +rate=3.404656038 +type=mul +date=7980 +[HKD:SEK] +source=HKD +target=SEK +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[HKD:SGD] +source=HKD +target=SGD +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[HKD:USD] +source=HKD +target=USD +intermediate= +rate=2.719190894 +type=mul +date=7980 +[HKD:ZQP] +source=HKD +target=ZQP +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[ILS:ATS] +source=ILS +target=ATS +intermediate= +rate=3.263086259 +type=mul +date=7980 +[ILS:AUD] +source=ILS +target=AUD +intermediate= +rate=6.256718257 +type=div +date=7980 +[ILS:BEF] +source=ILS +target=BEF +intermediate= +rate=1.957477254 +type=mul +date=7980 +[ILS:BNG] +source=ILS +target=BNG +intermediate= +rate=3.602720866 +type=div +date=7980 +[ILS:BRL] +source=ILS +target=BRL +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[ILS:CAD] +source=ILS +target=CAD +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[ILS:CHF] +source=ILS +target=CHF +intermediate= +rate=6.425556130 +type=mul +date=7980 +[ILS:CNY] +source=ILS +target=CNY +intermediate= +rate=1.603904066 +type=mul +date=7980 +[ILS:DEM] +source=ILS +target=DEM +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[ILS:DKK] +source=ILS +target=DKK +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[ILS:DTR] +source=ILS +target=DTR +intermediate= +rate=1.097156205 +type=mul +date=7980 +[ILS:EGP] +source=ILS +target=EGP +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[ILS:ELE] +source=ILS +target=ELE +intermediate= +rate=3.512062261 +type=mul +date=7980 +[ILS:ESP] +source=ILS +target=ESP +intermediate= +rate=1.923546746 +type=mul +date=7980 +[ILS:EUR] +source=ILS +target=EUR +intermediate= +rate=6.589432607 +type=div +date=7980 +[ILS:FRF] +source=ILS +target=FRF +intermediate= +rate=2.022700003 +type=mul +date=7980 +[ILS:GBP] +source=ILS +target=GBP +intermediate= +rate=6.836397577 +type=mul +date=7980 +[ILS:GRD] +source=ILS +target=GRD +intermediate= +rate=4.879973975 +type=div +date=7980 +[ILS:HKD] +source=ILS +target=HKD +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ILS:INR] +source=ILS +target=INR +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ILS:ISK] +source=ILS +target=ISK +intermediate= +rate=5.235992979 +type=mul +date=7980 +[ILS:ITL] +source=ILS +target=ITL +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[ILS:JPY] +source=ILS +target=JPY +intermediate= +rate=5.603419056 +type=div +date=7980 +[ILS:LAM] +source=ILS +target=LAM +intermediate= +rate=4.090117450 +type=mul +date=7980 +[ILS:MXN] +source=ILS +target=MXN +intermediate= +rate=1.870369966 +type=div +date=7980 +[ILS:NLG] +source=ILS +target=NLG +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[ILS:NOK] +source=ILS +target=NOK +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[ILS:NZD] +source=ILS +target=NZD +intermediate= +rate=3.222885872 +type=mul +date=7980 +[ILS:PLZ] +source=ILS +target=PLZ +intermediate= +rate=4.888018011 +type=mul +date=7980 +[ILS:PTE] +source=ILS +target=PTE +intermediate= +rate=5.323336842 +type=div +date=7980 +[ILS:RUR] +source=ILS +target=RUR +intermediate= +rate=1.626980335 +type=mul +date=7980 +[ILS:RYE] +source=ILS +target=RYE +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[ILS:SBD] +source=ILS +target=SBD +intermediate= +rate=6.709123645 +type=div +date=7980 +[ILS:SEK] +source=ILS +target=SEK +intermediate= +rate=3.776005554 +type=mul +date=7980 +[ILS:SGD] +source=ILS +target=SGD +intermediate= +rate=1.534397447 +type=mul +date=7980 +[ILS:USD] +source=ILS +target=USD +intermediate= +rate=4.479296184 +type=div +date=7980 +[ILS:ZQP] +source=ILS +target=ZQP +intermediate= +rate=5.894523188 +type=div +date=7980 +[INR:ATS] +source=INR +target=ATS +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[INR:AUD] +source=INR +target=AUD +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[INR:BEF] +source=INR +target=BEF +intermediate= +rate=6.864727834 +type=div +date=7980 +[INR:BNG] +source=INR +target=BNG +intermediate= +rate=3.399891177 +type=mul +date=7980 +[INR:BRL] +source=INR +target=BRL +intermediate= +rate=3.130305640 +type=mul +date=7980 +[INR:CAD] +source=INR +target=CAD +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[INR:CHF] +source=INR +target=CHF +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[INR:CNY] +source=INR +target=CNY +intermediate= +rate=5.126989305 +type=div +date=7980 +[INR:DEM] +source=INR +target=DEM +intermediate= +rate=4.066522536 +type=div +date=7980 +[INR:DKK] +source=INR +target=DKK +intermediate= +rate=1.590131454 +type=mul +date=7980 +[INR:DTR] +source=INR +target=DTR +intermediate= +rate=2.108709673 +type=mul +date=7980 +[INR:EGP] +source=INR +target=EGP +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[INR:ELE] +source=INR +target=ELE +intermediate= +rate=6.234425137 +type=mul +date=7980 +[INR:ESP] +source=INR +target=ESP +intermediate= +rate=1.896181169 +type=div +date=7980 +[INR:EUR] +source=INR +target=EUR +intermediate= +rate=2.358560653 +type=mul +date=7980 +[INR:FRF] +source=INR +target=FRF +intermediate= +rate=3.860243186 +type=div +date=7980 +[INR:GBP] +source=INR +target=GBP +intermediate= +rate=2.045742150 +type=mul +date=7980 +[INR:GRD] +source=INR +target=GRD +intermediate= +rate=1.607815984 +type=mul +date=7980 +[INR:HKD] +source=INR +target=HKD +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[INR:ILS] +source=INR +target=ILS +intermediate= +rate=6.541988996 +type=mul +date=7980 +[INR:ISK] +source=INR +target=ISK +intermediate= +rate=3.882590697 +type=div +date=7980 +[INR:ITL] +source=INR +target=ITL +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[INR:JPY] +source=INR +target=JPY +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[INR:LAM] +source=INR +target=LAM +intermediate= +rate=2.105735849 +type=div +date=7980 +[INR:MXN] +source=INR +target=MXN +intermediate= +rate=1.874599539 +type=div +date=7980 +[INR:NLG] +source=INR +target=NLG +intermediate= +rate=4.588425154 +type=mul +date=7980 +[INR:NOK] +source=INR +target=NOK +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[INR:NZD] +source=INR +target=NZD +intermediate= +rate=4.642322773 +type=div +date=7980 +[INR:PLZ] +source=INR +target=PLZ +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[INR:PTE] +source=INR +target=PTE +intermediate= +rate=1.434064504 +type=mul +date=7980 +[INR:RUR] +source=INR +target=RUR +intermediate= +rate=6.286901135 +type=mul +date=7980 +[INR:RYE] +source=INR +target=RYE +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[INR:SBD] +source=INR +target=SBD +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[INR:SEK] +source=INR +target=SEK +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[INR:SGD] +source=INR +target=SGD +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[INR:USD] +source=INR +target=USD +intermediate= +rate=4.425932292 +type=div +date=7980 +[INR:ZQP] +source=INR +target=ZQP +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ISK:ATS] +source=ISK +target=ATS +intermediate= +rate=1.535140266 +type=mul +date=7980 +[ISK:AUD] +source=ISK +target=AUD +intermediate= +rate=1.866533913 +type=div +date=7980 +[ISK:BEF] +source=ISK +target=BEF +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[ISK:BNG] +source=ISK +target=BNG +intermediate= +rate=2.975338578 +type=div +date=7980 +[ISK:BRL] +source=ISK +target=BRL +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ISK:CAD] +source=ISK +target=CAD +intermediate= +rate=5.492320138 +type=div +date=7980 +[ISK:CHF] +source=ISK +target=CHF +intermediate= +rate=3.500664541 +type=mul +date=7980 +[ISK:CNY] +source=ISK +target=CNY +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[ISK:DEM] +source=ISK +target=DEM +intermediate= +rate=5.474230813 +type=mul +date=7980 +[ISK:DKK] +source=ISK +target=DKK +intermediate= +rate=3.460138934 +type=div +date=7980 +[ISK:DTR] +source=ISK +target=DTR +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[ISK:EGP] +source=ISK +target=EGP +intermediate= +rate=6.427354653 +type=div +date=7980 +[ISK:ELE] +source=ISK +target=ELE +intermediate= +rate=5.114059550 +type=mul +date=7980 +[ISK:ESP] +source=ISK +target=ESP +intermediate= +rate=6.815459581 +type=div +date=7980 +[ISK:EUR] +source=ISK +target=EUR +intermediate= +rate=1.177335632 +type=div +date=7980 +[ISK:FRF] +source=ISK +target=FRF +intermediate= +rate=6.400495397 +type=div +date=7980 +[ISK:GBP] +source=ISK +target=GBP +intermediate= +rate=2.691085066 +type=div +date=7980 +[ISK:GRD] +source=ISK +target=GRD +intermediate= +rate=4.952048100 +type=div +date=7980 +[ISK:HKD] +source=ISK +target=HKD +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[ISK:ILS] +source=ISK +target=ILS +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[ISK:INR] +source=ISK +target=INR +intermediate= +rate=2.157473750 +type=div +date=7980 +[ISK:ITL] +source=ISK +target=ITL +intermediate= +rate=4.906808853 +type=mul +date=7980 +[ISK:JPY] +source=ISK +target=JPY +intermediate= +rate=4.718802057 +type=mul +date=7980 +[ISK:LAM] +source=ISK +target=LAM +intermediate= +rate=6.512147017 +type=mul +date=7980 +[ISK:MXN] +source=ISK +target=MXN +intermediate= +rate=4.233499711 +type=mul +date=7980 +[ISK:NLG] +source=ISK +target=NLG +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[ISK:NOK] +source=ISK +target=NOK +intermediate= +rate=5.385982979 +type=div +date=7980 +[ISK:NZD] +source=ISK +target=NZD +intermediate= +rate=3.914357197 +type=mul +date=7980 +[ISK:PLZ] +source=ISK +target=PLZ +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[ISK:PTE] +source=ISK +target=PTE +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[ISK:RUR] +source=ISK +target=RUR +intermediate= +rate=2.026215861 +type=div +date=7980 +[ISK:RYE] +source=ISK +target=RYE +intermediate= +rate=6.822020231 +type=div +date=7980 +[ISK:SBD] +source=ISK +target=SBD +intermediate= +rate=2.010907223 +type=div +date=7980 +[ISK:SEK] +source=ISK +target=SEK +intermediate= +rate=6.585903567 +type=mul +date=7980 +[ISK:SGD] +source=ISK +target=SGD +intermediate= +rate=4.147164735 +type=div +date=7980 +[ISK:USD] +source=ISK +target=USD +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[ISK:ZQP] +source=ISK +target=ZQP +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[ITL:ATS] +source=ITL +target=ATS +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[ITL:AUD] +source=ITL +target=AUD +intermediate= +rate=1.925413386 +type=mul +date=7980 +[ITL:BEF] +source=ITL +target=BEF +intermediate= +rate=2.329071610 +type=div +date=7980 +[ITL:BNG] +source=ITL +target=BNG +intermediate= +rate=2.069986680 +type=div +date=7980 +[ITL:BRL] +source=ITL +target=BRL +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[ITL:CAD] +source=ITL +target=CAD +intermediate= +rate=3.953000498 +type=div +date=7980 +[ITL:CHF] +source=ITL +target=CHF +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[ITL:CNY] +source=ITL +target=CNY +intermediate= +rate=5.960156330 +type=div +date=7980 +[ITL:DEM] +source=ITL +target=DEM +intermediate= +rate=4.113141108 +type=div +date=7980 +[ITL:DKK] +source=ITL +target=DKK +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[ITL:DTR] +source=ITL +target=DTR +intermediate= +rate=2.854005228 +type=div +date=7980 +[ITL:EGP] +source=ITL +target=EGP +intermediate= +rate=5.225741747 +type=mul +date=7980 +[ITL:ELE] +source=ITL +target=ELE +intermediate= +rate=5.532193263 +type=div +date=7980 +[ITL:ESP] +source=ITL +target=ESP +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[ITL:EUR] +source=ITL +target=EUR +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[ITL:FRF] +source=ITL +target=FRF +intermediate= +rate=4.219991459 +type=div +date=7980 +[ITL:GBP] +source=ITL +target=GBP +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ITL:GRD] +source=ITL +target=GRD +intermediate= +rate=1.217886732 +type=mul +date=7980 +[ITL:HKD] +source=ITL +target=HKD +intermediate= +rate=6.733922558 +type=mul +date=7980 +[ITL:ILS] +source=ITL +target=ILS +intermediate= +rate=3.169714352 +type=div +date=7980 +[ITL:INR] +source=ITL +target=INR +intermediate= +rate=5.136709935 +type=div +date=7980 +[ITL:ISK] +source=ITL +target=ISK +intermediate= +rate=1.872054236 +type=mul +date=7980 +[ITL:JPY] +source=ITL +target=JPY +intermediate= +rate=4.388662562 +type=div +date=7980 +[ITL:LAM] +source=ITL +target=LAM +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[ITL:MXN] +source=ITL +target=MXN +intermediate= +rate=5.935821262 +type=mul +date=7980 +[ITL:NLG] +source=ITL +target=NLG +intermediate= +rate=3.315271242 +type=div +date=7980 +[ITL:NOK] +source=ITL +target=NOK +intermediate= +rate=1.534353941 +type=div +date=7980 +[ITL:NZD] +source=ITL +target=NZD +intermediate= +rate=5.677924939 +type=div +date=7980 +[ITL:PLZ] +source=ITL +target=PLZ +intermediate= +rate=4.520579986 +type=div +date=7980 +[ITL:PTE] +source=ITL +target=PTE +intermediate= +rate=3.666525995 +type=div +date=7980 +[ITL:RUR] +source=ITL +target=RUR +intermediate= +rate=3.582287578 +type=div +date=7980 +[ITL:RYE] +source=ITL +target=RYE +intermediate= +rate=1.146826278 +type=div +date=7980 +[ITL:SBD] +source=ITL +target=SBD +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ITL:SEK] +source=ITL +target=SEK +intermediate= +rate=5.779522502 +type=div +date=7980 +[ITL:SGD] +source=ITL +target=SGD +intermediate= +rate=4.583466320 +type=mul +date=7980 +[ITL:USD] +source=ITL +target=USD +intermediate= +rate=6.882045391 +type=mul +date=7980 +[ITL:ZQP] +source=ITL +target=ZQP +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[JPY:ATS] +source=JPY +target=ATS +intermediate= +rate=2.636709680 +type=div +date=7980 +[JPY:AUD] +source=JPY +target=AUD +intermediate= +rate=4.369371542 +type=div +date=7980 +[JPY:BEF] +source=JPY +target=BEF +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[JPY:BNG] +source=JPY +target=BNG +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[JPY:BRL] +source=JPY +target=BRL +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[JPY:CAD] +source=JPY +target=CAD +intermediate= +rate=1.672932306 +type=div +date=7980 +[JPY:CHF] +source=JPY +target=CHF +intermediate= +rate=6.745232310 +type=mul +date=7980 +[JPY:CNY] +source=JPY +target=CNY +intermediate= +rate=6.561881303 +type=mul +date=7980 +[JPY:DEM] +source=JPY +target=DEM +intermediate= +rate=6.946749804 +type=mul +date=7980 +[JPY:DKK] +source=JPY +target=DKK +intermediate= +rate=6.591483337 +type=mul +date=7980 +[JPY:DTR] +source=JPY +target=DTR +intermediate= +rate=6.685525329 +type=mul +date=7980 +[JPY:EGP] +source=JPY +target=EGP +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[JPY:ELE] +source=JPY +target=ELE +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[JPY:ESP] +source=JPY +target=ESP +intermediate= +rate=4.205377710 +type=div +date=7980 +[JPY:EUR] +source=JPY +target=EUR +intermediate= +rate=2.808684319 +type=mul +date=7980 +[JPY:FRF] +source=JPY +target=FRF +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[JPY:GBP] +source=JPY +target=GBP +intermediate= +rate=1.108344481 +type=mul +date=7980 +[JPY:GRD] +source=JPY +target=GRD +intermediate= +rate=6.616096301 +type=div +date=7980 +[JPY:HKD] +source=JPY +target=HKD +intermediate= +rate=4.319613056 +type=mul +date=7980 +[JPY:ILS] +source=JPY +target=ILS +intermediate= +rate=2.689546461 +type=div +date=7980 +[JPY:INR] +source=JPY +target=INR +intermediate= +rate=6.199719601 +type=mul +date=7980 +[JPY:ISK] +source=JPY +target=ISK +intermediate= +rate=2.980923977 +type=mul +date=7980 +[JPY:ITL] +source=JPY +target=ITL +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[JPY:LAM] +source=JPY +target=LAM +intermediate= +rate=2.198278364 +type=mul +date=7980 +[JPY:MXN] +source=JPY +target=MXN +intermediate= +rate=4.804142167 +type=mul +date=7980 +[JPY:NLG] +source=JPY +target=NLG +intermediate= +rate=2.156156198 +type=mul +date=7980 +[JPY:NOK] +source=JPY +target=NOK +intermediate= +rate=1.867544940 +type=mul +date=7980 +[JPY:NZD] +source=JPY +target=NZD +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[JPY:PLZ] +source=JPY +target=PLZ +intermediate= +rate=2.403292055 +type=mul +date=7980 +[JPY:PTE] +source=JPY +target=PTE +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[JPY:RUR] +source=JPY +target=RUR +intermediate= +rate=5.294459963 +type=div +date=7980 +[JPY:RYE] +source=JPY +target=RYE +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[JPY:SBD] +source=JPY +target=SBD +intermediate= +rate=1.538495737 +type=div +date=7980 +[JPY:SEK] +source=JPY +target=SEK +intermediate= +rate=4.061218370 +type=mul +date=7980 +[JPY:SGD] +source=JPY +target=SGD +intermediate= +rate=4.410056504 +type=mul +date=7980 +[JPY:USD] +source=JPY +target=USD +intermediate= +rate=4.344690181 +type=mul +date=7980 +[JPY:ZQP] +source=JPY +target=ZQP +intermediate= +rate=3.478584711 +type=mul +date=7980 +[LAM:ATS] +source=LAM +target=ATS +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[LAM:AUD] +source=LAM +target=AUD +intermediate= +rate=2.276346800 +type=mul +date=7980 +[LAM:BEF] +source=LAM +target=BEF +intermediate= +rate=1.770421262 +type=div +date=7980 +[LAM:BNG] +source=LAM +target=BNG +intermediate= +rate=2.774002602 +type=div +date=7980 +[LAM:BRL] +source=LAM +target=BRL +intermediate= +rate=1.932584628 +type=mul +date=7980 +[LAM:CAD] +source=LAM +target=CAD +intermediate= +rate=6.103958511 +type=div +date=7980 +[LAM:CHF] +source=LAM +target=CHF +intermediate= +rate=3.446609918 +type=div +date=7980 +[LAM:CNY] +source=LAM +target=CNY +intermediate= +rate=6.109517162 +type=mul +date=7980 +[LAM:DEM] +source=LAM +target=DEM +intermediate= +rate=6.520890894 +type=div +date=7980 +[LAM:DKK] +source=LAM +target=DKK +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[LAM:DTR] +source=LAM +target=DTR +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[LAM:EGP] +source=LAM +target=EGP +intermediate= +rate=1.303661604 +type=mul +date=7980 +[LAM:ELE] +source=LAM +target=ELE +intermediate= +rate=6.455300824 +type=mul +date=7980 +[LAM:ESP] +source=LAM +target=ESP +intermediate= +rate=2.484388696 +type=mul +date=7980 +[LAM:EUR] +source=LAM +target=EUR +intermediate= +rate=3.533690624 +type=div +date=7980 +[LAM:FRF] +source=LAM +target=FRF +intermediate=BNG +rate=0.000000000 +type=tri +date=7980 +[LAM:GBP] +source=LAM +target=GBP +intermediate= +rate=3.909015661 +type=div +date=7980 +[LAM:GRD] +source=LAM +target=GRD +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[LAM:HKD] +source=LAM +target=HKD +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[LAM:ILS] +source=LAM +target=ILS +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[LAM:INR] +source=LAM +target=INR +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[LAM:ISK] +source=LAM +target=ISK +intermediate= +rate=4.546324644 +type=div +date=7980 +[LAM:ITL] +source=LAM +target=ITL +intermediate= +rate=4.620525706 +type=mul +date=7980 +[LAM:JPY] +source=LAM +target=JPY +intermediate= +rate=3.132682002 +type=div +date=7980 +[LAM:MXN] +source=LAM +target=MXN +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[LAM:NLG] +source=LAM +target=NLG +intermediate= +rate=2.348038528 +type=mul +date=7980 +[LAM:NOK] +source=LAM +target=NOK +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[LAM:NZD] +source=LAM +target=NZD +intermediate= +rate=6.573005618 +type=div +date=7980 +[LAM:PLZ] +source=LAM +target=PLZ +intermediate= +rate=2.263724439 +type=div +date=7980 +[LAM:PTE] +source=LAM +target=PTE +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[LAM:RUR] +source=LAM +target=RUR +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[LAM:RYE] +source=LAM +target=RYE +intermediate= +rate=3.973880549 +type=div +date=7980 +[LAM:SBD] +source=LAM +target=SBD +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[LAM:SEK] +source=LAM +target=SEK +intermediate= +rate=5.945834306 +type=mul +date=7980 +[LAM:SGD] +source=LAM +target=SGD +intermediate= +rate=3.057112412 +type=div +date=7980 +[LAM:USD] +source=LAM +target=USD +intermediate= +rate=6.181748808 +type=mul +date=7980 +[LAM:ZQP] +source=LAM +target=ZQP +intermediate= +rate=6.254378075 +type=div +date=7980 +[MXN:ATS] +source=MXN +target=ATS +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[MXN:AUD] +source=MXN +target=AUD +intermediate= +rate=1.566703623 +type=mul +date=7980 +[MXN:BEF] +source=MXN +target=BEF +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[MXN:BNG] +source=MXN +target=BNG +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[MXN:BRL] +source=MXN +target=BRL +intermediate= +rate=1.651613236 +type=mul +date=7980 +[MXN:CAD] +source=MXN +target=CAD +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[MXN:CHF] +source=MXN +target=CHF +intermediate= +rate=3.209140223 +type=mul +date=7980 +[MXN:CNY] +source=MXN +target=CNY +intermediate= +rate=1.115525710 +type=mul +date=7980 +[MXN:DEM] +source=MXN +target=DEM +intermediate= +rate=5.550769072 +type=mul +date=7980 +[MXN:DKK] +source=MXN +target=DKK +intermediate= +rate=1.013150003 +type=mul +date=7980 +[MXN:DTR] +source=MXN +target=DTR +intermediate= +rate=5.105874126 +type=mul +date=7980 +[MXN:EGP] +source=MXN +target=EGP +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[MXN:ELE] +source=MXN +target=ELE +intermediate= +rate=3.700407078 +type=mul +date=7980 +[MXN:ESP] +source=MXN +target=ESP +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[MXN:EUR] +source=MXN +target=EUR +intermediate= +rate=2.238219774 +type=div +date=7980 +[MXN:FRF] +source=MXN +target=FRF +intermediate= +rate=5.192934576 +type=mul +date=7980 +[MXN:GBP] +source=MXN +target=GBP +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[MXN:GRD] +source=MXN +target=GRD +intermediate= +rate=6.448665121 +type=mul +date=7980 +[MXN:HKD] +source=MXN +target=HKD +intermediate= +rate=1.231979194 +type=mul +date=7980 +[MXN:ILS] +source=MXN +target=ILS +intermediate= +rate=3.412094650 +type=mul +date=7980 +[MXN:INR] +source=MXN +target=INR +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[MXN:ISK] +source=MXN +target=ISK +intermediate= +rate=2.925062439 +type=mul +date=7980 +[MXN:ITL] +source=MXN +target=ITL +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[MXN:JPY] +source=MXN +target=JPY +intermediate= +rate=2.515193556 +type=mul +date=7980 +[MXN:LAM] +source=MXN +target=LAM +intermediate= +rate=2.228929470 +type=mul +date=7980 +[MXN:NLG] +source=MXN +target=NLG +intermediate= +rate=4.905089658 +type=mul +date=7980 +[MXN:NOK] +source=MXN +target=NOK +intermediate= +rate=2.343089001 +type=div +date=7980 +[MXN:NZD] +source=MXN +target=NZD +intermediate= +rate=5.972703923 +type=div +date=7980 +[MXN:PLZ] +source=MXN +target=PLZ +intermediate= +rate=5.791646100 +type=div +date=7980 +[MXN:PTE] +source=MXN +target=PTE +intermediate= +rate=1.176414887 +type=div +date=7980 +[MXN:RUR] +source=MXN +target=RUR +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[MXN:RYE] +source=MXN +target=RYE +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[MXN:SBD] +source=MXN +target=SBD +intermediate= +rate=2.833993822 +type=mul +date=7980 +[MXN:SEK] +source=MXN +target=SEK +intermediate= +rate=6.859954419 +type=div +date=7980 +[MXN:SGD] +source=MXN +target=SGD +intermediate= +rate=4.441568129 +type=mul +date=7980 +[MXN:USD] +source=MXN +target=USD +intermediate= +rate=4.771589297 +type=div +date=7980 +[MXN:ZQP] +source=MXN +target=ZQP +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[NLG:ATS] +source=NLG +target=ATS +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[NLG:AUD] +source=NLG +target=AUD +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[NLG:BEF] +source=NLG +target=BEF +intermediate= +rate=1.834083580 +type=mul +date=7980 +[NLG:BNG] +source=NLG +target=BNG +intermediate= +rate=1.120047949 +type=div +date=7980 +[NLG:BRL] +source=NLG +target=BRL +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[NLG:CAD] +source=NLG +target=CAD +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[NLG:CHF] +source=NLG +target=CHF +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[NLG:CNY] +source=NLG +target=CNY +intermediate= +rate=1.330712606 +type=mul +date=7980 +[NLG:DEM] +source=NLG +target=DEM +intermediate= +rate=2.395887431 +type=mul +date=7980 +[NLG:DKK] +source=NLG +target=DKK +intermediate= +rate=5.717461453 +type=mul +date=7980 +[NLG:DTR] +source=NLG +target=DTR +intermediate= +rate=1.283004018 +type=mul +date=7980 +[NLG:EGP] +source=NLG +target=EGP +intermediate= +rate=4.142317586 +type=mul +date=7980 +[NLG:ELE] +source=NLG +target=ELE +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[NLG:ESP] +source=NLG +target=ESP +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[NLG:EUR] +source=NLG +target=EUR +intermediate= +rate=5.371534333 +type=div +date=7980 +[NLG:FRF] +source=NLG +target=FRF +intermediate= +rate=6.960725444 +type=div +date=7980 +[NLG:GBP] +source=NLG +target=GBP +intermediate= +rate=5.377206032 +type=mul +date=7980 +[NLG:GRD] +source=NLG +target=GRD +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[NLG:HKD] +source=NLG +target=HKD +intermediate= +rate=2.955428062 +type=div +date=7980 +[NLG:ILS] +source=NLG +target=ILS +intermediate= +rate=1.111636713 +type=div +date=7980 +[NLG:INR] +source=NLG +target=INR +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[NLG:ISK] +source=NLG +target=ISK +intermediate= +rate=6.735988481 +type=div +date=7980 +[NLG:ITL] +source=NLG +target=ITL +intermediate= +rate=1.731556254 +type=div +date=7980 +[NLG:JPY] +source=NLG +target=JPY +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[NLG:LAM] +source=NLG +target=LAM +intermediate= +rate=4.685657682 +type=mul +date=7980 +[NLG:MXN] +source=NLG +target=MXN +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[NLG:NOK] +source=NLG +target=NOK +intermediate= +rate=5.477871374 +type=div +date=7980 +[NLG:NZD] +source=NLG +target=NZD +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[NLG:PLZ] +source=NLG +target=PLZ +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[NLG:PTE] +source=NLG +target=PTE +intermediate= +rate=2.774288962 +type=mul +date=7980 +[NLG:RUR] +source=NLG +target=RUR +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[NLG:RYE] +source=NLG +target=RYE +intermediate= +rate=6.878045022 +type=mul +date=7980 +[NLG:SBD] +source=NLG +target=SBD +intermediate=PLZ +rate=0.000000000 +type=tri +date=7980 +[NLG:SEK] +source=NLG +target=SEK +intermediate= +rate=6.676026206 +type=mul +date=7980 +[NLG:SGD] +source=NLG +target=SGD +intermediate= +rate=6.103221767 +type=mul +date=7980 +[NLG:USD] +source=NLG +target=USD +intermediate= +rate=5.778217664 +type=mul +date=7980 +[NLG:ZQP] +source=NLG +target=ZQP +intermediate= +rate=5.330535264 +type=div +date=7980 +[NOK:ATS] +source=NOK +target=ATS +intermediate= +rate=2.967913468 +type=mul +date=7980 +[NOK:AUD] +source=NOK +target=AUD +intermediate= +rate=4.015277426 +type=mul +date=7980 +[NOK:BEF] +source=NOK +target=BEF +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[NOK:BNG] +source=NOK +target=BNG +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[NOK:BRL] +source=NOK +target=BRL +intermediate= +rate=4.803242252 +type=mul +date=7980 +[NOK:CAD] +source=NOK +target=CAD +intermediate= +rate=4.654483847 +type=mul +date=7980 +[NOK:CHF] +source=NOK +target=CHF +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[NOK:CNY] +source=NOK +target=CNY +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[NOK:DEM] +source=NOK +target=DEM +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[NOK:DKK] +source=NOK +target=DKK +intermediate= +rate=2.197677418 +type=div +date=7980 +[NOK:DTR] +source=NOK +target=DTR +intermediate= +rate=4.237866166 +type=div +date=7980 +[NOK:EGP] +source=NOK +target=EGP +intermediate= +rate=6.136839333 +type=mul +date=7980 +[NOK:ELE] +source=NOK +target=ELE +intermediate= +rate=4.270658976 +type=mul +date=7980 +[NOK:ESP] +source=NOK +target=ESP +intermediate= +rate=1.365733290 +type=mul +date=7980 +[NOK:EUR] +source=NOK +target=EUR +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[NOK:FRF] +source=NOK +target=FRF +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[NOK:GBP] +source=NOK +target=GBP +intermediate= +rate=3.154918861 +type=mul +date=7980 +[NOK:GRD] +source=NOK +target=GRD +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[NOK:HKD] +source=NOK +target=HKD +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[NOK:ILS] +source=NOK +target=ILS +intermediate= +rate=1.706985790 +type=mul +date=7980 +[NOK:INR] +source=NOK +target=INR +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[NOK:ISK] +source=NOK +target=ISK +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[NOK:ITL] +source=NOK +target=ITL +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[NOK:JPY] +source=NOK +target=JPY +intermediate= +rate=2.183804410 +type=div +date=7980 +[NOK:LAM] +source=NOK +target=LAM +intermediate= +rate=3.804723743 +type=mul +date=7980 +[NOK:MXN] +source=NOK +target=MXN +intermediate= +rate=1.674786674 +type=mul +date=7980 +[NOK:NLG] +source=NOK +target=NLG +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[NOK:NZD] +source=NOK +target=NZD +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[NOK:PLZ] +source=NOK +target=PLZ +intermediate= +rate=3.858973757 +type=mul +date=7980 +[NOK:PTE] +source=NOK +target=PTE +intermediate= +rate=2.714980480 +type=mul +date=7980 +[NOK:RUR] +source=NOK +target=RUR +intermediate= +rate=5.631554424 +type=div +date=7980 +[NOK:RYE] +source=NOK +target=RYE +intermediate= +rate=2.469757689 +type=mul +date=7980 +[NOK:SBD] +source=NOK +target=SBD +intermediate= +rate=1.518743682 +type=mul +date=7980 +[NOK:SEK] +source=NOK +target=SEK +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[NOK:SGD] +source=NOK +target=SGD +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[NOK:USD] +source=NOK +target=USD +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[NOK:ZQP] +source=NOK +target=ZQP +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[NZD:ATS] +source=NZD +target=ATS +intermediate= +rate=2.508305810 +type=div +date=7980 +[NZD:AUD] +source=NZD +target=AUD +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[NZD:BEF] +source=NZD +target=BEF +intermediate= +rate=6.407834078 +type=mul +date=7980 +[NZD:BNG] +source=NZD +target=BNG +intermediate= +rate=6.970071844 +type=mul +date=7980 +[NZD:BRL] +source=NZD +target=BRL +intermediate= +rate=2.737141518 +type=mul +date=7980 +[NZD:CAD] +source=NZD +target=CAD +intermediate= +rate=4.408344462 +type=div +date=7980 +[NZD:CHF] +source=NZD +target=CHF +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[NZD:CNY] +source=NZD +target=CNY +intermediate= +rate=3.280559011 +type=div +date=7980 +[NZD:DEM] +source=NZD +target=DEM +intermediate= +rate=2.843510399 +type=div +date=7980 +[NZD:DKK] +source=NZD +target=DKK +intermediate= +rate=5.581184427 +type=mul +date=7980 +[NZD:DTR] +source=NZD +target=DTR +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[NZD:EGP] +source=NZD +target=EGP +intermediate= +rate=4.215359255 +type=div +date=7980 +[NZD:ELE] +source=NZD +target=ELE +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[NZD:ESP] +source=NZD +target=ESP +intermediate= +rate=3.540283527 +type=mul +date=7980 +[NZD:EUR] +source=NZD +target=EUR +intermediate= +rate=1.317346377 +type=div +date=7980 +[NZD:FRF] +source=NZD +target=FRF +intermediate= +rate=6.066859940 +type=div +date=7980 +[NZD:GBP] +source=NZD +target=GBP +intermediate= +rate=4.318679301 +type=div +date=7980 +[NZD:GRD] +source=NZD +target=GRD +intermediate= +rate=3.901881426 +type=mul +date=7980 +[NZD:HKD] +source=NZD +target=HKD +intermediate= +rate=4.187372693 +type=div +date=7980 +[NZD:ILS] +source=NZD +target=ILS +intermediate= +rate=5.766677547 +type=mul +date=7980 +[NZD:INR] +source=NZD +target=INR +intermediate= +rate=5.475400819 +type=div +date=7980 +[NZD:ISK] +source=NZD +target=ISK +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[NZD:ITL] +source=NZD +target=ITL +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[NZD:JPY] +source=NZD +target=JPY +intermediate= +rate=2.436371433 +type=mul +date=7980 +[NZD:LAM] +source=NZD +target=LAM +intermediate= +rate=5.501873833 +type=div +date=7980 +[NZD:MXN] +source=NZD +target=MXN +intermediate= +rate=2.790806966 +type=div +date=7980 +[NZD:NLG] +source=NZD +target=NLG +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[NZD:NOK] +source=NZD +target=NOK +intermediate= +rate=4.234132077 +type=div +date=7980 +[NZD:PLZ] +source=NZD +target=PLZ +intermediate= +rate=2.894577269 +type=div +date=7980 +[NZD:PTE] +source=NZD +target=PTE +intermediate= +rate=4.475124619 +type=div +date=7980 +[NZD:RUR] +source=NZD +target=RUR +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[NZD:RYE] +source=NZD +target=RYE +intermediate= +rate=5.830891436 +type=div +date=7980 +[NZD:SBD] +source=NZD +target=SBD +intermediate= +rate=5.817814422 +type=mul +date=7980 +[NZD:SEK] +source=NZD +target=SEK +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[NZD:SGD] +source=NZD +target=SGD +intermediate= +rate=3.535088440 +type=mul +date=7980 +[NZD:USD] +source=NZD +target=USD +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[NZD:ZQP] +source=NZD +target=ZQP +intermediate= +rate=5.962499627 +type=div +date=7980 +[PLZ:ATS] +source=PLZ +target=ATS +intermediate= +rate=5.840229023 +type=div +date=7980 +[PLZ:AUD] +source=PLZ +target=AUD +intermediate= +rate=2.302494119 +type=div +date=7980 +[PLZ:BEF] +source=PLZ +target=BEF +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[PLZ:BNG] +source=PLZ +target=BNG +intermediate= +rate=5.744414437 +type=div +date=7980 +[PLZ:BRL] +source=PLZ +target=BRL +intermediate= +rate=1.402267116 +type=mul +date=7980 +[PLZ:CAD] +source=PLZ +target=CAD +intermediate= +rate=5.813250385 +type=div +date=7980 +[PLZ:CHF] +source=PLZ +target=CHF +intermediate= +rate=4.342914099 +type=mul +date=7980 +[PLZ:CNY] +source=PLZ +target=CNY +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[PLZ:DEM] +source=PLZ +target=DEM +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[PLZ:DKK] +source=PLZ +target=DKK +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[PLZ:DTR] +source=PLZ +target=DTR +intermediate= +rate=3.877611500 +type=mul +date=7980 +[PLZ:EGP] +source=PLZ +target=EGP +intermediate= +rate=6.610163662 +type=mul +date=7980 +[PLZ:ELE] +source=PLZ +target=ELE +intermediate= +rate=2.050522721 +type=div +date=7980 +[PLZ:ESP] +source=PLZ +target=ESP +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[PLZ:EUR] +source=PLZ +target=EUR +intermediate= +rate=1.806126043 +type=div +date=7980 +[PLZ:FRF] +source=PLZ +target=FRF +intermediate= +rate=2.373171111 +type=div +date=7980 +[PLZ:GBP] +source=PLZ +target=GBP +intermediate= +rate=2.734567028 +type=mul +date=7980 +[PLZ:GRD] +source=PLZ +target=GRD +intermediate= +rate=6.564454940 +type=mul +date=7980 +[PLZ:HKD] +source=PLZ +target=HKD +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[PLZ:ILS] +source=PLZ +target=ILS +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[PLZ:INR] +source=PLZ +target=INR +intermediate= +rate=1.757768097 +type=mul +date=7980 +[PLZ:ISK] +source=PLZ +target=ISK +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[PLZ:ITL] +source=PLZ +target=ITL +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[PLZ:JPY] +source=PLZ +target=JPY +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[PLZ:LAM] +source=PLZ +target=LAM +intermediate= +rate=6.819219090 +type=div +date=7980 +[PLZ:MXN] +source=PLZ +target=MXN +intermediate= +rate=3.916648226 +type=div +date=7980 +[PLZ:NLG] +source=PLZ +target=NLG +intermediate= +rate=2.672400183 +type=mul +date=7980 +[PLZ:NOK] +source=PLZ +target=NOK +intermediate= +rate=4.200701401 +type=mul +date=7980 +[PLZ:NZD] +source=PLZ +target=NZD +intermediate= +rate=4.876534542 +type=mul +date=7980 +[PLZ:PTE] +source=PLZ +target=PTE +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[PLZ:RUR] +source=PLZ +target=RUR +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[PLZ:RYE] +source=PLZ +target=RYE +intermediate= +rate=3.585499724 +type=mul +date=7980 +[PLZ:SBD] +source=PLZ +target=SBD +intermediate= +rate=4.152502242 +type=div +date=7980 +[PLZ:SEK] +source=PLZ +target=SEK +intermediate= +rate=3.443346734 +type=mul +date=7980 +[PLZ:SGD] +source=PLZ +target=SGD +intermediate= +rate=6.270745899 +type=mul +date=7980 +[PLZ:USD] +source=PLZ +target=USD +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[PLZ:ZQP] +source=PLZ +target=ZQP +intermediate= +rate=3.266032308 +type=mul +date=7980 +[PTE:ATS] +source=PTE +target=ATS +intermediate= +rate=6.074408177 +type=mul +date=7980 +[PTE:AUD] +source=PTE +target=AUD +intermediate= +rate=6.514163371 +type=mul +date=7980 +[PTE:BEF] +source=PTE +target=BEF +intermediate= +rate=6.056922288 +type=mul +date=7980 +[PTE:BNG] +source=PTE +target=BNG +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[PTE:BRL] +source=PTE +target=BRL +intermediate= +rate=6.965968237 +type=mul +date=7980 +[PTE:CAD] +source=PTE +target=CAD +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[PTE:CHF] +source=PTE +target=CHF +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[PTE:CNY] +source=PTE +target=CNY +intermediate= +rate=1.865605496 +type=mul +date=7980 +[PTE:DEM] +source=PTE +target=DEM +intermediate= +rate=3.500464425 +type=div +date=7980 +[PTE:DKK] +source=PTE +target=DKK +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[PTE:DTR] +source=PTE +target=DTR +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[PTE:EGP] +source=PTE +target=EGP +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[PTE:ELE] +source=PTE +target=ELE +intermediate= +rate=1.170266498 +type=div +date=7980 +[PTE:ESP] +source=PTE +target=ESP +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[PTE:EUR] +source=PTE +target=EUR +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[PTE:FRF] +source=PTE +target=FRF +intermediate= +rate=5.502348830 +type=div +date=7980 +[PTE:GBP] +source=PTE +target=GBP +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[PTE:GRD] +source=PTE +target=GRD +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[PTE:HKD] +source=PTE +target=HKD +intermediate= +rate=6.862031860 +type=div +date=7980 +[PTE:ILS] +source=PTE +target=ILS +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[PTE:INR] +source=PTE +target=INR +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[PTE:ISK] +source=PTE +target=ISK +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[PTE:ITL] +source=PTE +target=ITL +intermediate=BRL +rate=0.000000000 +type=tri +date=7980 +[PTE:JPY] +source=PTE +target=JPY +intermediate= +rate=1.529966143 +type=div +date=7980 +[PTE:LAM] +source=PTE +target=LAM +intermediate= +rate=2.191613830 +type=div +date=7980 +[PTE:MXN] +source=PTE +target=MXN +intermediate= +rate=5.427744263 +type=div +date=7980 +[PTE:NLG] +source=PTE +target=NLG +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[PTE:NOK] +source=PTE +target=NOK +intermediate= +rate=3.888251176 +type=mul +date=7980 +[PTE:NZD] +source=PTE +target=NZD +intermediate= +rate=3.289903022 +type=mul +date=7980 +[PTE:PLZ] +source=PTE +target=PLZ +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[PTE:RUR] +source=PTE +target=RUR +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[PTE:RYE] +source=PTE +target=RYE +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[PTE:SBD] +source=PTE +target=SBD +intermediate= +rate=4.649550616 +type=mul +date=7980 +[PTE:SEK] +source=PTE +target=SEK +intermediate= +rate=5.802410983 +type=mul +date=7980 +[PTE:SGD] +source=PTE +target=SGD +intermediate= +rate=1.940229843 +type=mul +date=7980 +[PTE:USD] +source=PTE +target=USD +intermediate= +rate=4.418275439 +type=mul +date=7980 +[PTE:ZQP] +source=PTE +target=ZQP +intermediate= +rate=3.200499177 +type=mul +date=7980 +[RUR:ATS] +source=RUR +target=ATS +intermediate= +rate=6.392131093 +type=div +date=7980 +[RUR:AUD] +source=RUR +target=AUD +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[RUR:BEF] +source=RUR +target=BEF +intermediate= +rate=2.393959106 +type=div +date=7980 +[RUR:BNG] +source=RUR +target=BNG +intermediate= +rate=2.997273885 +type=div +date=7980 +[RUR:BRL] +source=RUR +target=BRL +intermediate= +rate=2.615992956 +type=mul +date=7980 +[RUR:CAD] +source=RUR +target=CAD +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[RUR:CHF] +source=RUR +target=CHF +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[RUR:CNY] +source=RUR +target=CNY +intermediate= +rate=4.406263741 +type=div +date=7980 +[RUR:DEM] +source=RUR +target=DEM +intermediate= +rate=4.970253622 +type=div +date=7980 +[RUR:DKK] +source=RUR +target=DKK +intermediate= +rate=5.266379865 +type=div +date=7980 +[RUR:DTR] +source=RUR +target=DTR +intermediate= +rate=4.677518574 +type=mul +date=7980 +[RUR:EGP] +source=RUR +target=EGP +intermediate= +rate=4.227255360 +type=div +date=7980 +[RUR:ELE] +source=RUR +target=ELE +intermediate= +rate=3.392291044 +type=mul +date=7980 +[RUR:ESP] +source=RUR +target=ESP +intermediate= +rate=6.846545929 +type=div +date=7980 +[RUR:EUR] +source=RUR +target=EUR +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[RUR:FRF] +source=RUR +target=FRF +intermediate= +rate=4.875429115 +type=div +date=7980 +[RUR:GBP] +source=RUR +target=GBP +intermediate= +rate=2.311061499 +type=mul +date=7980 +[RUR:GRD] +source=RUR +target=GRD +intermediate=AUD +rate=0.000000000 +type=tri +date=7980 +[RUR:HKD] +source=RUR +target=HKD +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[RUR:ILS] +source=RUR +target=ILS +intermediate= +rate=1.926891492 +type=mul +date=7980 +[RUR:INR] +source=RUR +target=INR +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[RUR:ISK] +source=RUR +target=ISK +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[RUR:ITL] +source=RUR +target=ITL +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[RUR:JPY] +source=RUR +target=JPY +intermediate= +rate=1.086646199 +type=div +date=7980 +[RUR:LAM] +source=RUR +target=LAM +intermediate= +rate=6.449555518 +type=mul +date=7980 +[RUR:MXN] +source=RUR +target=MXN +intermediate= +rate=3.497875792 +type=div +date=7980 +[RUR:NLG] +source=RUR +target=NLG +intermediate= +rate=4.956795850 +type=mul +date=7980 +[RUR:NOK] +source=RUR +target=NOK +intermediate= +rate=1.920349283 +type=div +date=7980 +[RUR:NZD] +source=RUR +target=NZD +intermediate=DTR +rate=0.000000000 +type=tri +date=7980 +[RUR:PLZ] +source=RUR +target=PLZ +intermediate= +rate=4.410909253 +type=div +date=7980 +[RUR:PTE] +source=RUR +target=PTE +intermediate= +rate=5.689224200 +type=div +date=7980 +[RUR:RYE] +source=RUR +target=RYE +intermediate= +rate=1.781461921 +type=div +date=7980 +[RUR:SBD] +source=RUR +target=SBD +intermediate= +rate=5.072764417 +type=mul +date=7980 +[RUR:SEK] +source=RUR +target=SEK +intermediate= +rate=1.249105160 +type=mul +date=7980 +[RUR:SGD] +source=RUR +target=SGD +intermediate= +rate=3.715888553 +type=div +date=7980 +[RUR:USD] +source=RUR +target=USD +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[RUR:ZQP] +source=RUR +target=ZQP +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[RYE:ATS] +source=RYE +target=ATS +intermediate= +rate=3.797282965 +type=div +date=7980 +[RYE:AUD] +source=RYE +target=AUD +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[RYE:BEF] +source=RYE +target=BEF +intermediate=SEK +rate=0.000000000 +type=tri +date=7980 +[RYE:BNG] +source=RYE +target=BNG +intermediate= +rate=1.696421514 +type=div +date=7980 +[RYE:BRL] +source=RYE +target=BRL +intermediate= +rate=5.407358154 +type=mul +date=7980 +[RYE:CAD] +source=RYE +target=CAD +intermediate= +rate=3.241817480 +type=mul +date=7980 +[RYE:CHF] +source=RYE +target=CHF +intermediate= +rate=5.509036357 +type=div +date=7980 +[RYE:CNY] +source=RYE +target=CNY +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[RYE:DEM] +source=RYE +target=DEM +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[RYE:DKK] +source=RYE +target=DKK +intermediate= +rate=5.075920172 +type=div +date=7980 +[RYE:DTR] +source=RYE +target=DTR +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[RYE:EGP] +source=RYE +target=EGP +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[RYE:ELE] +source=RYE +target=ELE +intermediate= +rate=4.131537099 +type=mul +date=7980 +[RYE:ESP] +source=RYE +target=ESP +intermediate= +rate=4.977099384 +type=div +date=7980 +[RYE:EUR] +source=RYE +target=EUR +intermediate= +rate=6.784596675 +type=div +date=7980 +[RYE:FRF] +source=RYE +target=FRF +intermediate= +rate=4.792794386 +type=div +date=7980 +[RYE:GBP] +source=RYE +target=GBP +intermediate= +rate=3.970188173 +type=div +date=7980 +[RYE:GRD] +source=RYE +target=GRD +intermediate= +rate=1.866381480 +type=mul +date=7980 +[RYE:HKD] +source=RYE +target=HKD +intermediate= +rate=4.022883501 +type=mul +date=7980 +[RYE:ILS] +source=RYE +target=ILS +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[RYE:INR] +source=RYE +target=INR +intermediate= +rate=6.159672228 +type=mul +date=7980 +[RYE:ISK] +source=RYE +target=ISK +intermediate= +rate=5.656593634 +type=div +date=7980 +[RYE:ITL] +source=RYE +target=ITL +intermediate= +rate=3.933568439 +type=mul +date=7980 +[RYE:JPY] +source=RYE +target=JPY +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[RYE:LAM] +source=RYE +target=LAM +intermediate= +rate=6.491755761 +type=mul +date=7980 +[RYE:MXN] +source=RYE +target=MXN +intermediate= +rate=2.154909608 +type=mul +date=7980 +[RYE:NLG] +source=RYE +target=NLG +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[RYE:NOK] +source=RYE +target=NOK +intermediate= +rate=5.470562678 +type=mul +date=7980 +[RYE:NZD] +source=RYE +target=NZD +intermediate= +rate=4.490153585 +type=div +date=7980 +[RYE:PLZ] +source=RYE +target=PLZ +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[RYE:PTE] +source=RYE +target=PTE +intermediate= +rate=3.068401304 +type=mul +date=7980 +[RYE:RUR] +source=RYE +target=RUR +intermediate= +rate=4.954127604 +type=mul +date=7980 +[RYE:SBD] +source=RYE +target=SBD +intermediate= +rate=4.974506157 +type=mul +date=7980 +[RYE:SEK] +source=RYE +target=SEK +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[RYE:SGD] +source=RYE +target=SGD +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[RYE:USD] +source=RYE +target=USD +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[RYE:ZQP] +source=RYE +target=ZQP +intermediate= +rate=6.113938481 +type=mul +date=7980 +[SBD:ATS] +source=SBD +target=ATS +intermediate= +rate=5.301077306 +type=mul +date=7980 +[SBD:AUD] +source=SBD +target=AUD +intermediate= +rate=4.106408962 +type=mul +date=7980 +[SBD:BEF] +source=SBD +target=BEF +intermediate=MXN +rate=0.000000000 +type=tri +date=7980 +[SBD:BNG] +source=SBD +target=BNG +intermediate= +rate=3.545131895 +type=mul +date=7980 +[SBD:BRL] +source=SBD +target=BRL +intermediate= +rate=5.229777554 +type=mul +date=7980 +[SBD:CAD] +source=SBD +target=CAD +intermediate=DKK +rate=0.000000000 +type=tri +date=7980 +[SBD:CHF] +source=SBD +target=CHF +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[SBD:CNY] +source=SBD +target=CNY +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[SBD:DEM] +source=SBD +target=DEM +intermediate=USD +rate=0.000000000 +type=tri +date=7980 +[SBD:DKK] +source=SBD +target=DKK +intermediate= +rate=5.248457001 +type=mul +date=7980 +[SBD:DTR] +source=SBD +target=DTR +intermediate= +rate=3.876895722 +type=div +date=7980 +[SBD:EGP] +source=SBD +target=EGP +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[SBD:ELE] +source=SBD +target=ELE +intermediate= +rate=3.088542949 +type=div +date=7980 +[SBD:ESP] +source=SBD +target=ESP +intermediate= +rate=5.445672793 +type=div +date=7980 +[SBD:EUR] +source=SBD +target=EUR +intermediate= +rate=1.755232583 +type=mul +date=7980 +[SBD:FRF] +source=SBD +target=FRF +intermediate= +rate=3.760035502 +type=mul +date=7980 +[SBD:GBP] +source=SBD +target=GBP +intermediate= +rate=3.768450370 +type=mul +date=7980 +[SBD:GRD] +source=SBD +target=GRD +intermediate= +rate=2.372709129 +type=div +date=7980 +[SBD:HKD] +source=SBD +target=HKD +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[SBD:ILS] +source=SBD +target=ILS +intermediate= +rate=6.110081374 +type=mul +date=7980 +[SBD:INR] +source=SBD +target=INR +intermediate= +rate=2.584741185 +type=mul +date=7980 +[SBD:ISK] +source=SBD +target=ISK +intermediate= +rate=3.705205567 +type=mul +date=7980 +[SBD:ITL] +source=SBD +target=ITL +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[SBD:JPY] +source=SBD +target=JPY +intermediate= +rate=3.458136444 +type=div +date=7980 +[SBD:LAM] +source=SBD +target=LAM +intermediate= +rate=2.304531679 +type=div +date=7980 +[SBD:MXN] +source=SBD +target=MXN +intermediate= +rate=5.614252667 +type=mul +date=7980 +[SBD:NLG] +source=SBD +target=NLG +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[SBD:NOK] +source=SBD +target=NOK +intermediate= +rate=1.281695896 +type=mul +date=7980 +[SBD:NZD] +source=SBD +target=NZD +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[SBD:PLZ] +source=SBD +target=PLZ +intermediate= +rate=4.193936293 +type=mul +date=7980 +[SBD:PTE] +source=SBD +target=PTE +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[SBD:RUR] +source=SBD +target=RUR +intermediate= +rate=2.407400494 +type=div +date=7980 +[SBD:RYE] +source=SBD +target=RYE +intermediate=PTE +rate=0.000000000 +type=tri +date=7980 +[SBD:SEK] +source=SBD +target=SEK +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[SBD:SGD] +source=SBD +target=SGD +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[SBD:USD] +source=SBD +target=USD +intermediate= +rate=6.440967208 +type=div +date=7980 +[SBD:ZQP] +source=SBD +target=ZQP +intermediate= +rate=5.375091927 +type=mul +date=7980 +[SEK:ATS] +source=SEK +target=ATS +intermediate= +rate=6.948168495 +type=div +date=7980 +[SEK:AUD] +source=SEK +target=AUD +intermediate= +rate=1.623476696 +type=mul +date=7980 +[SEK:BEF] +source=SEK +target=BEF +intermediate=ISK +rate=0.000000000 +type=tri +date=7980 +[SEK:BNG] +source=SEK +target=BNG +intermediate= +rate=3.160348836 +type=div +date=7980 +[SEK:BRL] +source=SEK +target=BRL +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[SEK:CAD] +source=SEK +target=CAD +intermediate= +rate=4.505383156 +type=mul +date=7980 +[SEK:CHF] +source=SEK +target=CHF +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[SEK:CNY] +source=SEK +target=CNY +intermediate= +rate=1.089490031 +type=div +date=7980 +[SEK:DEM] +source=SEK +target=DEM +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[SEK:DKK] +source=SEK +target=DKK +intermediate= +rate=1.643396378 +type=div +date=7980 +[SEK:DTR] +source=SEK +target=DTR +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[SEK:EGP] +source=SEK +target=EGP +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[SEK:ELE] +source=SEK +target=ELE +intermediate= +rate=2.615707876 +type=mul +date=7980 +[SEK:ESP] +source=SEK +target=ESP +intermediate= +rate=1.967972031 +type=mul +date=7980 +[SEK:EUR] +source=SEK +target=EUR +intermediate= +rate=4.988152476 +type=mul +date=7980 +[SEK:FRF] +source=SEK +target=FRF +intermediate= +rate=6.227739138 +type=mul +date=7980 +[SEK:GBP] +source=SEK +target=GBP +intermediate= +rate=1.566750549 +type=div +date=7980 +[SEK:GRD] +source=SEK +target=GRD +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[SEK:HKD] +source=SEK +target=HKD +intermediate= +rate=4.171449671 +type=div +date=7980 +[SEK:ILS] +source=SEK +target=ILS +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[SEK:INR] +source=SEK +target=INR +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[SEK:ISK] +source=SEK +target=ISK +intermediate= +rate=3.960990021 +type=mul +date=7980 +[SEK:ITL] +source=SEK +target=ITL +intermediate= +rate=6.530626633 +type=div +date=7980 +[SEK:JPY] +source=SEK +target=JPY +intermediate=EGP +rate=0.000000000 +type=tri +date=7980 +[SEK:LAM] +source=SEK +target=LAM +intermediate= +rate=4.949232721 +type=mul +date=7980 +[SEK:MXN] +source=SEK +target=MXN +intermediate=RUR +rate=0.000000000 +type=tri +date=7980 +[SEK:NLG] +source=SEK +target=NLG +intermediate= +rate=4.211587003 +type=mul +date=7980 +[SEK:NOK] +source=SEK +target=NOK +intermediate= +rate=5.500876027 +type=div +date=7980 +[SEK:NZD] +source=SEK +target=NZD +intermediate= +rate=3.433590725 +type=mul +date=7980 +[SEK:PLZ] +source=SEK +target=PLZ +intermediate= +rate=2.279949711 +type=div +date=7980 +[SEK:PTE] +source=SEK +target=PTE +intermediate= +rate=5.358119475 +type=mul +date=7980 +[SEK:RUR] +source=SEK +target=RUR +intermediate= +rate=5.820282052 +type=mul +date=7980 +[SEK:RYE] +source=SEK +target=RYE +intermediate= +rate=5.713314033 +type=div +date=7980 +[SEK:SBD] +source=SEK +target=SBD +intermediate= +rate=3.658105411 +type=div +date=7980 +[SEK:SGD] +source=SEK +target=SGD +intermediate=NLG +rate=0.000000000 +type=tri +date=7980 +[SEK:USD] +source=SEK +target=USD +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[SEK:ZQP] +source=SEK +target=ZQP +intermediate= +rate=6.316810523 +type=div +date=7980 +[SGD:ATS] +source=SGD +target=ATS +intermediate= +rate=6.627304737 +type=div +date=7980 +[SGD:AUD] +source=SGD +target=AUD +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[SGD:BEF] +source=SGD +target=BEF +intermediate= +rate=1.685888917 +type=mul +date=7980 +[SGD:BNG] +source=SGD +target=BNG +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[SGD:BRL] +source=SGD +target=BRL +intermediate= +rate=3.759005778 +type=div +date=7980 +[SGD:CAD] +source=SGD +target=CAD +intermediate= +rate=6.318206004 +type=div +date=7980 +[SGD:CHF] +source=SGD +target=CHF +intermediate= +rate=1.978970408 +type=div +date=7980 +[SGD:CNY] +source=SGD +target=CNY +intermediate= +rate=3.642130906 +type=div +date=7980 +[SGD:DEM] +source=SGD +target=DEM +intermediate= +rate=3.685639808 +type=mul +date=7980 +[SGD:DKK] +source=SGD +target=DKK +intermediate= +rate=3.513123377 +type=mul +date=7980 +[SGD:DTR] +source=SGD +target=DTR +intermediate= +rate=4.720043361 +type=mul +date=7980 +[SGD:EGP] +source=SGD +target=EGP +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[SGD:ELE] +source=SGD +target=ELE +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[SGD:ESP] +source=SGD +target=ESP +intermediate= +rate=3.569141931 +type=mul +date=7980 +[SGD:EUR] +source=SGD +target=EUR +intermediate=ELE +rate=0.000000000 +type=tri +date=7980 +[SGD:FRF] +source=SGD +target=FRF +intermediate= +rate=1.884814479 +type=div +date=7980 +[SGD:GBP] +source=SGD +target=GBP +intermediate= +rate=2.107079180 +type=mul +date=7980 +[SGD:GRD] +source=SGD +target=GRD +intermediate= +rate=5.629790554 +type=div +date=7980 +[SGD:HKD] +source=SGD +target=HKD +intermediate= +rate=3.117535114 +type=mul +date=7980 +[SGD:ILS] +source=SGD +target=ILS +intermediate= +rate=4.101457951 +type=div +date=7980 +[SGD:INR] +source=SGD +target=INR +intermediate= +rate=1.194231613 +type=mul +date=7980 +[SGD:ISK] +source=SGD +target=ISK +intermediate=BEF +rate=0.000000000 +type=tri +date=7980 +[SGD:ITL] +source=SGD +target=ITL +intermediate=CNY +rate=0.000000000 +type=tri +date=7980 +[SGD:JPY] +source=SGD +target=JPY +intermediate= +rate=2.029399863 +type=mul +date=7980 +[SGD:LAM] +source=SGD +target=LAM +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[SGD:MXN] +source=SGD +target=MXN +intermediate= +rate=1.749128834 +type=mul +date=7980 +[SGD:NLG] +source=SGD +target=NLG +intermediate=GBP +rate=0.000000000 +type=tri +date=7980 +[SGD:NOK] +source=SGD +target=NOK +intermediate= +rate=3.088187537 +type=div +date=7980 +[SGD:NZD] +source=SGD +target=NZD +intermediate= +rate=6.310075614 +type=div +date=7980 +[SGD:PLZ] +source=SGD +target=PLZ +intermediate= +rate=4.725139554 +type=div +date=7980 +[SGD:PTE] +source=SGD +target=PTE +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[SGD:RUR] +source=SGD +target=RUR +intermediate= +rate=4.784159623 +type=div +date=7980 +[SGD:RYE] +source=SGD +target=RYE +intermediate= +rate=6.074165807 +type=div +date=7980 +[SGD:SBD] +source=SGD +target=SBD +intermediate= +rate=6.771992603 +type=div +date=7980 +[SGD:SEK] +source=SGD +target=SEK +intermediate=CAD +rate=0.000000000 +type=tri +date=7980 +[SGD:USD] +source=SGD +target=USD +intermediate= +rate=2.137760532 +type=mul +date=7980 +[SGD:ZQP] +source=SGD +target=ZQP +intermediate= +rate=2.604810901 +type=div +date=7980 +[USD:ATS] +source=USD +target=ATS +intermediate= +rate=2.523193132 +type=div +date=7980 +[USD:AUD] +source=USD +target=AUD +intermediate= +rate=5.516032937 +type=mul +date=7980 +[USD:BEF] +source=USD +target=BEF +intermediate= +rate=6.369410931 +type=mul +date=7980 +[USD:BNG] +source=USD +target=BNG +intermediate=GRD +rate=0.000000000 +type=tri +date=7980 +[USD:BRL] +source=USD +target=BRL +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[USD:CAD] +source=USD +target=CAD +intermediate= +rate=4.569056285 +type=mul +date=7980 +[USD:CHF] +source=USD +target=CHF +intermediate=ILS +rate=0.000000000 +type=tri +date=7980 +[USD:CNY] +source=USD +target=CNY +intermediate= +rate=4.969180344 +type=div +date=7980 +[USD:DEM] +source=USD +target=DEM +intermediate= +rate=5.792888495 +type=mul +date=7980 +[USD:DKK] +source=USD +target=DKK +intermediate=ATS +rate=0.000000000 +type=tri +date=7980 +[USD:DTR] +source=USD +target=DTR +intermediate= +rate=4.784352188 +type=div +date=7980 +[USD:EGP] +source=USD +target=EGP +intermediate=ITL +rate=0.000000000 +type=tri +date=7980 +[USD:ELE] +source=USD +target=ELE +intermediate=SBD +rate=0.000000000 +type=tri +date=7980 +[USD:ESP] +source=USD +target=ESP +intermediate= +rate=1.711173582 +type=div +date=7980 +[USD:EUR] +source=USD +target=EUR +intermediate= +rate=4.472410325 +type=mul +date=7980 +[USD:FRF] +source=USD +target=FRF +intermediate= +rate=1.779311210 +type=div +date=7980 +[USD:GBP] +source=USD +target=GBP +intermediate= +rate=4.999030734 +type=mul +date=7980 +[USD:GRD] +source=USD +target=GRD +intermediate=ZQP +rate=0.000000000 +type=tri +date=7980 +[USD:HKD] +source=USD +target=HKD +intermediate= +rate=3.503869425 +type=mul +date=7980 +[USD:ILS] +source=USD +target=ILS +intermediate= +rate=1.801506748 +type=mul +date=7980 +[USD:INR] +source=USD +target=INR +intermediate= +rate=5.148367411 +type=mul +date=7980 +[USD:ISK] +source=USD +target=ISK +intermediate= +rate=4.887893249 +type=mul +date=7980 +[USD:ITL] +source=USD +target=ITL +intermediate=FRF +rate=0.000000000 +type=tri +date=7980 +[USD:JPY] +source=USD +target=JPY +intermediate= +rate=3.341997697 +type=mul +date=7980 +[USD:LAM] +source=USD +target=LAM +intermediate= +rate=1.921452560 +type=div +date=7980 +[USD:MXN] +source=USD +target=MXN +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[USD:NLG] +source=USD +target=NLG +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[USD:NOK] +source=USD +target=NOK +intermediate= +rate=4.674986568 +type=mul +date=7980 +[USD:NZD] +source=USD +target=NZD +intermediate= +rate=1.153018641 +type=div +date=7980 +[USD:PLZ] +source=USD +target=PLZ +intermediate= +rate=1.806029562 +type=mul +date=7980 +[USD:PTE] +source=USD +target=PTE +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 +[USD:RUR] +source=USD +target=RUR +intermediate= +rate=4.910190658 +type=div +date=7980 +[USD:RYE] +source=USD +target=RYE +intermediate= +rate=5.455101331 +type=div +date=7980 +[USD:SBD] +source=USD +target=SBD +intermediate= +rate=6.703331924 +type=div +date=7980 +[USD:SEK] +source=USD +target=SEK +intermediate= +rate=6.742846773 +type=div +date=7980 +[USD:SGD] +source=USD +target=SGD +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[USD:ZQP] +source=USD +target=ZQP +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[ZQP:ATS] +source=ZQP +target=ATS +intermediate= +rate=5.568171387 +type=mul +date=7980 +[ZQP:AUD] +source=ZQP +target=AUD +intermediate= +rate=1.225633702 +type=mul +date=7980 +[ZQP:BEF] +source=ZQP +target=BEF +intermediate=NZD +rate=0.000000000 +type=tri +date=7980 +[ZQP:BNG] +source=ZQP +target=BNG +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ZQP:BRL] +source=ZQP +target=BRL +intermediate= +rate=5.038049780 +type=div +date=7980 +[ZQP:CAD] +source=ZQP +target=CAD +intermediate= +rate=6.713222294 +type=mul +date=7980 +[ZQP:CHF] +source=ZQP +target=CHF +intermediate= +rate=1.634703176 +type=mul +date=7980 +[ZQP:CNY] +source=ZQP +target=CNY +intermediate=ESP +rate=0.000000000 +type=tri +date=7980 +[ZQP:DEM] +source=ZQP +target=DEM +intermediate= +rate=4.593576234 +type=mul +date=7980 +[ZQP:DKK] +source=ZQP +target=DKK +intermediate= +rate=5.201470708 +type=mul +date=7980 +[ZQP:DTR] +source=ZQP +target=DTR +intermediate=CHF +rate=0.000000000 +type=tri +date=7980 +[ZQP:EGP] +source=ZQP +target=EGP +intermediate=HKD +rate=0.000000000 +type=tri +date=7980 +[ZQP:ELE] +source=ZQP +target=ELE +intermediate=SGD +rate=0.000000000 +type=tri +date=7980 +[ZQP:ESP] +source=ZQP +target=ESP +intermediate=JPY +rate=0.000000000 +type=tri +date=7980 +[ZQP:EUR] +source=ZQP +target=EUR +intermediate= +rate=6.649464339 +type=mul +date=7980 +[ZQP:FRF] +source=ZQP +target=FRF +intermediate=LAM +rate=0.000000000 +type=tri +date=7980 +[ZQP:GBP] +source=ZQP +target=GBP +intermediate=EUR +rate=0.000000000 +type=tri +date=7980 +[ZQP:GRD] +source=ZQP +target=GRD +intermediate= +rate=5.159827132 +type=mul +date=7980 +[ZQP:HKD] +source=ZQP +target=HKD +intermediate= +rate=1.033331090 +type=div +date=7980 +[ZQP:ILS] +source=ZQP +target=ILS +intermediate= +rate=6.784289010 +type=div +date=7980 +[ZQP:INR] +source=ZQP +target=INR +intermediate= +rate=1.344910697 +type=mul +date=7980 +[ZQP:ISK] +source=ZQP +target=ISK +intermediate=NOK +rate=0.000000000 +type=tri +date=7980 +[ZQP:ITL] +source=ZQP +target=ITL +intermediate= +rate=4.711392760 +type=mul +date=7980 +[ZQP:JPY] +source=ZQP +target=JPY +intermediate= +rate=5.250221503 +type=mul +date=7980 +[ZQP:LAM] +source=ZQP +target=LAM +intermediate= +rate=3.048003611 +type=div +date=7980 +[ZQP:MXN] +source=ZQP +target=MXN +intermediate= +rate=3.949181694 +type=mul +date=7980 +[ZQP:NLG] +source=ZQP +target=NLG +intermediate= +rate=5.994409150 +type=div +date=7980 +[ZQP:NOK] +source=ZQP +target=NOK +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[ZQP:NZD] +source=ZQP +target=NZD +intermediate= +rate=6.093681197 +type=mul +date=7980 +[ZQP:PLZ] +source=ZQP +target=PLZ +intermediate= +rate=2.085860820 +type=div +date=7980 +[ZQP:PTE] +source=ZQP +target=PTE +intermediate= +rate=2.448073260 +type=div +date=7980 +[ZQP:RUR] +source=ZQP +target=RUR +intermediate=RYE +rate=0.000000000 +type=tri +date=7980 +[ZQP:RYE] +source=ZQP +target=RYE +intermediate=INR +rate=0.000000000 +type=tri +date=7980 +[ZQP:SBD] +source=ZQP +target=SBD +intermediate= +rate=5.979947206 +type=mul +date=7980 +[ZQP:SEK] +source=ZQP +target=SEK +intermediate= +rate=3.067827449 +type=mul +date=7980 +[ZQP:SGD] +source=ZQP +target=SGD +intermediate= +rate=5.680488452 +type=mul +date=7980 +[ZQP:USD] +source=ZQP +target=USD +intermediate=DEM +rate=0.000000000 +type=tri +date=7980 diff --git a/components/systools/source/run/stconst.pas b/components/systools/source/run/stconst.pas new file mode 100644 index 000000000..b7ed3dc1c --- /dev/null +++ b/components/systools/source/run/stconst.pas @@ -0,0 +1,848 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StConst.pas 4.04 *} +{*********************************************************} +{* SysTools: Base unit for SysTools *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +unit StConst; + {-Resource constants for SysTools} + +interface + +uses + SysUtils; + +const + StVersionStr = '4.04'; + +const + {string table constants for STREGINI} + stscFalseString = 0; + stscTrueString = 1; + stscNoFileKey = 2; + stscInvalidPKey = 3; + stscNoWin32S = 4; + stscCreateKeyFail = 5; + stscOpenKeyFail = 6; + stscIniWriteFail = 7; + stscRegWriteFail = 8; + stscNoKeyName = 9; + stscQueryKeyFail = 10; + stscEnumKeyFail = 11; + stscEnumValueFail = 12; + stscIniDeleteFail = 13; + stscKeyHasSubKeys = 14; + stscDeleteKeyFail = 15; + stscIniDelValueFail = 16; + stscRegDelValueFail = 17; + stscOutputFileExists = 18; + stscFileHasExtension = 19; + stscSaveKeyFail = 20; + stscNo16bitSupport = 21; + stscCantFindInputFile = 22; + stscLoadKeyFail = 23; + stscUnloadKeyFail = 24; + stscNotWinNTPlatform = 25; + stscBadOptionsKeyCombo = 26; + stscRestoreKeyFail = 27; + stscReplaceKeyFail = 28; + stscNoIniFileSupport = 29; + stscRemoteKeyIsOpen = 30; + stscConnectRemoteKeyFail = 31; + stscCloseRemoteKeyFail = 32; + stscFlushKeyFail = 33; + stscBufferDataSizesDif = 34; + stscKeyIsEmptyNotExists = 35; + stscGetSecurityFail = 36; + stscSetSecurityFail = 37; + stscByteArrayTooLarge = 38; + stscQueryValueFail = 39; + stscNoValueNameSpecified = 40; + + {string table constants for container classes} + stscNoCompare = 51; {Compare property must be set} + stscBadType = 52; {an incompatible class is passed to a method} + stscBadSize = 53; {bad size for TStDictionary, TStBits, TStCollection} + stscDupNode = 54; {attempt to add duplicate node to TStTree} + stscBadIndex = 55; {bad index passed to TStBits or large array} + stscBadWinMode = 56; {requires enhanced mode operation} + stscUnknownClass = 57; {container class name not registered} + stscUnknownNodeClass = 58; {container node class name not registered} + stscNoStoreData = 59; {container has no store data routine} + stscNoLoadData = 60; {container has no load data routine} + stscWrongClass = 61; {container class and streamed class not equal} + stscWrongNodeClass = 62; {container node class and streamed class not equal} + stscBadCompare = 63; {invalid compare function or unable to assign now} + stscTooManyCols = 64; {assign a matrix with >1 col to array} + stscBadColCount = 65; {assign a matrix with wrong col count to virtual matrix} + stscBadElSize = 66; {assign a matrix with wrong elem size to virtual matrix} + stscBadDups = 67; {setting Dups to False in a non-empty sorted collection} + + {string table constants for sorting unit} + stscTooManyFiles = 71; {too many merge files in TStSorter} + stscFileCreate = 72; {error creating file in TStSorter} + stscFileOpen = 73; {error opening file in TStSorter} + stscFileWrite = 74; {error writing file in TStSorter} + stscFileRead = 75; {error reading file in TStSorter} + stscBadState = 76; {TStSorter in wrong state} + + {string table constants for Bcd unit} + stscBcdBadFormat = 81; {bad BCD format} + stscBcdOverflow = 82; {BCD larger than 10**64} + stscBcdDivByZero = 83; {BCD divide by zero} + stscBcdBadInput = 84; {BCD negative input to sqrt, ln, or power} + stscBcdBufOverflow = 85; {buffer overflow in FormatBcd} + + stscNoVerInfo = 100; {no version info in file} + stscVerInfoFail = 101; {error reading version info} + +(* + {shell string constants} + stscShellVersionError = 110; {not available in this version of Shell32.dll} + stscShellFileOpSrcError = 111; {no source files specified} + stscShellFileOpDstError = 112; {no destination files specified} + stscShellFileOpMapError = 113; {mapping incomplete} + stscShellFormatError = 114; {format error} + stscShellFormatCancel = 115; {format cancelled} + stscShellFormatNoFormat = 116; {drive cannot be formatted} + stscShellFormatBadDrive = 117; {not removable drive} + stscTrayIconInvalidOS = 118; {bad OS (NT 3.51)} + stscTrayIconCantAdd = 119; {can't add icon to the tray} + stscTrayIconCantDelete = 120; {can't delete icon from the tray} + stscTrayIconError = 121; {general tray icon error} + stscBadDropTarget = 122; {drop target is not TWinControl} + stscCOMInitFailed = 123; {COInitialize failed} + stscNoPathSpecified = 124; {No destination path for shortcut} + stscIShellLinkError = 125; {Error creating IShellLink} + stscNotShortcut = 126; {File is not a shortcut} + stscTrayIconClose = 127; {Close} + stscTrayIconRestore = 128; {Restore} + stscInvalidTargetFile = 130; {Shortcut target file not found} + stscShellFileOpDelete = 131; {Can't use file mappings with delete op} + stscShellFileNotFound = 132; {One or more source files is missing} + stscTrayIconDuplicate = 133; {Cant' have more than one tray icon} + stscBadVerInfoKey = 134; {User-defined key not found in ver info} + stscImageListInvalid = 135; {No image list assigned.} +*) + stscBadVerInfoKey = 134; {User-defined key not found in ver info} + + {barcode errors} + stscInvalidUPCACodeLen = 140; + stscInvalidCharacter = 141; + stscInvalidCheckCharacter = 142; + stscInvalidUPCECodeLen = 143; + stscInvalidEAN8CodeLen = 144; + stscInvalidEAN13CodeLen = 145; + stscInvalidSupCodeLen = 146; + + {stexpr errors} + stscExprEmpty = 150; {empty expression} + stscExprBadNum = 151; {error in floating point number} + stscExprBadChar = 152; {unknown character} + stscExprOpndExp = 153; {expected function, number, sign, or (} + stscExprNumeric = 154; {numeric error} + stscExprBadExp = 155; {invalid expression} + stscExprOpndOvfl = 156; {operand stack overflow} + stscExprUnkFunc = 157; {unknown function identifier} + stscExprLParExp = 158; {left parenthesis expected} + stscExprRParExp = 159; {right parenthesis expected} + stscExprCommExp = 160; {list separator (comma) expected} + stscExprDupIdent = 161; {duplicate identifier} + + {ststat errors} + stscStatBadCount = 170; {unequal or bad counts of array elements} + stscStatBadParam = 171; {invalid parameter} + stscStatBadData = 172; {invalid data point in array} + stscStatNoConverge = 173; {no convergence in numerical routine} + + {stfin errors} + stscFinBadArg = 180; + stscFinNoConverge = 181; + + {stmime errors} + stscBadEncodeFmt = 190; + stscBadAttachment = 191; + stscDupeString = 192; + stscInStream = 193; + + {ststring errors} + stscOutOfBounds = 200; {Index out of string bounds} + + + {stBarPN errors} + stscInvalidLength = 210; + + {StHTML errors} + stscNoInputFile = 215; + stscNoOutputFile = 216; + stscInFileError = 217; + stscOutFileError = 218; + stscWordDelimiters = 219; + stscInvalidSLEntry = 220; + stscBadStream = 221; + + {StShlCtl constansts} + stscName = 230; + stscSize = 231; + stscType = 232; + stscModified = 233; + stscAttributes = 234; + stscFileFolder = 235; + stscSystemFolder = 236; + stscOriginalLoc = 237; + stscDateDeleted = 238; + stscFile = 239; + stscInvalidFolder = 240; + stscFolderReadOnly = 241; + + {StSpawnApplication errors} + stscInsufficientData= 250; + + {StMemoryMappedFile errors} + stscCreateFileFailed = 260; + stscFileMappingFailed= 261; + stscCreateViewFailed = 262; + stscBadOrigin = 263; + stscGetSizeFailed = 264; + + {buffered stream errors} + stscNilStream = 270; + stscNoSeekForRead = 271; + stscNoSeekForWrite = 272; + stscCannotWrite = 273; + stscBadTerminator = 274; + stscBadLineLength = 275; + stscCannotSetSize = 276; + + {RegEx errors} + stscUnknownError = 290; + stscExpandingClass = 291; + stscAlternationFollowsClosure = 292; + stscUnbalancedParens = 293; + stscFollowingClosure = 294; + stscPatternError = 295; + stscUnbalancedTag = 296; + stscNoPatterns = 297; + stscPatternTooLarge = 298; + stscStreamsNil = 299; + stscInTextStreamError = 300; + stscOutTextStreamError = 301; + stscClosureMaybeEmpty = 302; + stscInFileNotFound = 303; + stscREInFileError = 304; + stscOutFileDelete = 305; + stscOutFileCreate = 306; + + + {StNet errors 320-339} + stscNetNoManualCreate = 320; + stscNetUnknownError = 321; + stscNetGroupNotSpecified = 322; + stscNetDateSpecifiedOutOfRange = 323; + stscNetInvalidParameter = 324; + stscNetInvalidItemType = 325; + + {StNetConnection errors 330-334} + + {StNetPerformance errors 335-339} + + {StNetMessage errors 340-344} + + {StMoney errors 400-429} +// stscMoneyIdxOutOfRange = 400; //'Index out of range (%s)' + stscMoneyNilResult = 401; //'Nil result parameter' + stscMoneyNilParameter = 402; //'Nil parameter to operation' + stscMoneyCurrenciesNotMatch = 403; //'Currencies do not match' + stscMoneyNoExchangeRatesAvail = 410; //'No Exchange Rates Available' + stscMoneyInvalidExchangeParams = 411; //'Invalid exchange parameters' + stscMoneyInvalidTriangleExchange = 412; //'Invalid triangle exchange' + stscMoneyNoSuchExchange = 413; //'No exchange rate for %s->%s available' + stscMoneyMissingIntermediateRate = 414; //''Intermediate exchange rate for %s->%s missing' + stscMoneyInvalidExchRate = 415; //'Exchange rate is missing a property value' + stscMoneyTriExchUsesTriExch = 415; //'Triangular exchange rate is using triangular exchange rates' + + stscDecMathRoundPlaces = 423; //'Decimal math: the number of decimal places to round to must be betwen 0 and 16' + stscDecMathAsIntOverflow = 424; //'Decimal math: current value overflows an integer' + stscDecMathConversion = 425; //'Decimal math: string value not a valid number'; + stscDecMathDivByZero = 426; //'Decimal math: division by zero attempted' + stscDecMathNegExp = 427; //'Decimal math: cannot raise to a negative power'; + stscDecMathMultOverflow = 428; //'Decimal math: result overflowed during multiplication' + stscDecMathDivOverflow = 429; //'Decimal math: result overflowed during division' + + { Text Data Set, Merge, and Export errors } + stscTxtDatNoSuchField = 430; //'No such field' + stscTxtDatUniqueNameRequired = 431; //'Field name must be unique' + stscTxtDatUnhandledVariant = 432; //'Unhandled Variant Type' + stscTxtDatInvalidSchema = 433; //'Invalid Schema' + stscTxtDatRecordSetOpen = 434; //'Cannot perform this operation on an open record set' + + {PRNG errors 460-479} + stscPRNGDegFreedom = 460; //'StRandom: the number of degrees of freedom should be greater than zero' + stscPRNGBetaShape = 461; //'StRandom: the Beta distribution shape values should be greater than zero' + stscPRNGMean = 462; //'StRandom: the mean must be greater than zero' + stscPRNGGammaShape = 463; //'StRandom: the Gamma distribution shape must be greater than zero' + stscPRNGGammaScale = 464; //'StRandom: the Gamma distribution scale must be greater than zero' + stscPRNGStdDev = 465; //'StRandom: the standard deviation must be greater than zero' + stscPRNGWeibullShape = 466; //'StRandom: the Weibull distribution shape must be greater than zero' + stscPRNGWeibullScale = 467; //'StRandom: the Weibull distribution scale must be greater than zero' + stscPRNGLimit = 468; //'StRandom: the limit must be greater than zero' + stscPRNGUpperLimit = 469; //'StRandom: the upper limit must be greater than the lower limit' + stscPRNGErlangOrder = 470; //'StRandom: the Erlang distribution's order must be greater than zero' + +resourcestring + stscSysStringListFull = 'String list is full'; + stscSysBadStartDir = 'Invalid starting directory'; + + stscFalseStringS = 'FALSE'; + stscTrueStringS = 'TRUE'; + stscNoFileKeyS = 'No Ini File or Primary Key specified'; + stscInvalidPKeyS = 'Invalid primary key specified'; + stscNoWin32SS = 'RegIni Class not supported under Win32s'; + stscCreateKeyFailS = 'Failed to create key\nError Code: %d'; + stscOpenKeyFailS = 'Failed to open key\nError Code: %d'; + stscIniWriteFailS = 'Failed to write value to INI file'; + stscRegWriteFailS = 'Failed to write value to Registry\nError Code: %d'; + stscNoKeyNameS = 'No key name specified'; + stscQueryKeyFailS = 'Unable to query specified key\nError Code: %d'; + stscEnumKeyFailS = 'Unable to enumerate key\nError Code: %d'; + stscEnumValueFailS = 'Unable to enumerate value\nError Code: %d'; + stscIniDeleteFailS = 'Unable to delete section from INI file'; + stscKeyHasSubKeysS = 'Can not delete key which has subkeys (%d)'; + stscDeleteKeyFailS = 'Unable to delete key\nError Code: %d'; + stscIniDelValueFailS = 'Unable to delete value from INI file'; + stscRegDelValueFailS = 'Unable to delete value from key\nError Code: %d'; + stscOutputFileExistsS = 'Output file exists'; + stscFileHasExtensionS = 'File name can not have an extension'; + stscSaveKeyFailS = 'Unable to save key\nError Code: %d'; + stscNo16bitSupportS = 'Function not supported in 16-bit applications'; + stscCantFindInputFileS = 'Can not find input file'; + stscLoadKeyFailS = 'Unable to load key\nError Code: %d'; + stscUnloadKeyFailS = 'Unable to unload key\nErrorCode: %d'; + stscNotWinNTPlatformS = 'Function not supported on this platform'; + stscBadOptionsKeyComboS = 'Selection options incompatible\nwith specified primary key'; + stscRestoreKeyFailS = 'Unable to restore key\nError Code: %d'; + stscReplaceKeyFailS = 'Unable to replace key\nError Code: %d'; + stscNoIniFileSupportS = 'Function not supported on INI files'; + stscRemoteKeyIsOpenS = 'Remote key already open'; + stscConnectRemoteKeyFailS = 'Unable to connect to remote registry key\nError Code: %d'; + stscCloseRemoteKeyFailS = 'Unable to close remote registry key'; + stscFlushKeyFailS = 'Unable to flush specified key'; + stscBufferDataSizesDifS = 'Buffer size differs from data size\nBuffer: %d Data: %d'; + stscKeyIsEmptyNotExistsS = 'Specified Key is empty or does not exist'; + stscGetSecurityFailS = 'Failed to Get Security Information\nError Code: %d'; + stscSetSecurityFailS = 'Failed to Set Security Information\nError Code: %d'; + stscByteArrayTooLargeS = 'Size of byte array exceeds limit'; + stscQueryValueFailS = 'Unable to query value in key'; + stscNoValueNameSpecifiedS = 'No Value Name specified'; + + stscNoCompareS = 'Compare property must be set'; + stscBadTypeS = 'An incompatible class is passed to a method'; + stscBadSizeS = 'Bad size parameter'; + stscDupNodeS = 'Attempt to add duplicate node to TStTree'; + stscBadIndexS = 'Index is out of range'; + stscBadWinModeS = 'Requires enhanced mode operation for Windows 3.1x'; + stscUnknownClassS = 'Container class name %s read from stream is unregistered'; + stscUnknownNodeClassS = 'Node class name %s read from stream is unregistered'; + stscNoStoreDataS = 'Container''s StoreData property is unassigned'; + stscNoLoadDataS = 'Container''s LoadData property is unassigned'; + stscWrongClassS = 'Class name on stream differs from object''s class'; + stscWrongNodeClassS = 'Node class name on stream differs from object''s node class'; + stscBadCompareS = 'Unable to assign this compare function now'; + stscTooManyColsS = 'Cannot assign a matrix with more than 1 column to an array'; + stscBadColCountS = 'Can only assign a matrix to a virtual matrix if column counts are equal'; + stscBadElSizeS = 'Can only assign a matrix to a virtual matrix if element sizes are equal'; + stscBadDupsS = 'Can only set Duplicates to False in an empty sorted collection'; + + stscTooManyFilesS = 'Too many merge files in TStSorter'; + stscFileCreateS = 'Error creating file'; + stscFileOpenS = 'Error opening file'; + stscFileWriteS = 'Error writing file (bytes written <> bytes requested)'; + stscFileReadS = 'Error reading file (bytes read <> bytes requested)'; + stscBadStateS = 'TStSorter in wrong state'; + + stscBcdBadFormatS = 'Bad BCD format'; + stscBcdOverflowS = 'BCD larger than 10**64'; + stscBcdDivByZeroS = 'BCD divide by zero'; + stscBcdBadInputS = 'BCD negative input to sqrt, ln, or power'; + stscBcdBufOverflowS = 'Buffer overflow in FormatBcd'; + + stscNoVerInfoS = 'File does not contain version info'; + stscVerInfoFailS = 'Unable to read version info'; + +(* + stscShellVersionErrorS = 'Operation not supported in this version of the shell'; + stscShellFileOpSrcErrorS = 'No source files specified'; + stscShellFileOpDstErrorS = 'No destination files specified'; + stscShellFileOpMapErrorS = 'File mapping incomplete'; + stscShellFormatErrorS = 'Format failed'; + stscShellFormatCancelS = 'Format cancelled'; + stscShellFormatNoFormatS = 'Drive cannot be formatted'; + stscShellFormatBadDriveS = 'Invalid drive. Drive is not removable'; + stscTrayIconInvalidOSS = 'Operating system does not support tray icons'; + stscTrayIconCantAddS = 'Error adding tray icon'; + stscTrayIconCantDeleteS = 'Error removing tray icon'; + stscTrayIconErrorS = 'Tray icon error'; + stscBadDropTargetS = 'Drop target must be a TWinControl descendant'; + stscCOMInitFailedS = 'Cannot initialize COM'; + stscNoPathSpecifiedS = 'Destination directory not specified'; + stscIShellLinkErrorS = 'Error creating IShellLink'; + stscNotShortcutS = 'File is not a shortcut'; + stscTrayIconCloseS = '&Close'; + stscTrayIconRestoreS = '&Restore'; + stscInvalidTargetFileS = 'Cannot create shortcut. Target file does not exist'; + stscShellFileOpDeleteS = 'Cannot use file mappings in a delete operation'; + stscShellFileNotFoundS = 'Source file error, file not found'; + stscTrayIconDuplicateS = 'Cannot have more than one StTrayIcon per application'; + stscBadVerInfoKeyS = 'The specified key cannnot be found in version info'; + stscImageListInvalidS = 'ImageList is not assigned'; +*) + stscBadVerInfoKeyS = 'The specified key cannnot be found in version info'; + + stscInvalidUPCACodeLenS = 'Invalid code length (must be 11 or 12)'; + stscInvalidCharacterS = 'Invalid character'; + stscInvalidCheckCharacterS = 'Invalid check character'; + stscInvalidUPCECodeLenS = 'Invalid code length (must be 6)'; + stscInvalidEAN8CodeLenS = 'Invalid code length (must be 7 or 8)'; + stscInvalidEAN13CodeLenS = 'Invalid code length (must be 12 or 13)'; + stscInvalidSupCodeLenS = 'Invalid supplemental code length (must be 2 or 5)'; + + stscFinBadArgS = 'Invalid argument to financial function'; + stscFinNoConvergeS = 'Function does not converge'; + + stscExprEmptyS = 'Empty expression'; + stscExprBadNumS = 'Error in floating point number'; + stscExprBadCharS = 'Unknown character'; + stscExprOpndExpS = 'Expected function, number, sign, or ('; + stscExprNumericS = 'Numeric error'; + stscExprBadExpS = 'Invalid expression'; + stscExprOpndOvflS = 'Operand stack overflow'; + stscExprUnkFuncS = 'Unknown function identifier'; + stscExprLParExpS = 'Left parenthesis expected'; + stscExprRParExpS = 'Right parenthesis expected'; + stscExprCommExpS = 'List separator expected'; + stscExprDupIdentS = 'Duplicate identifier'; + + stscBadEncodeFmtS = 'Encoding Format Not Supported'; + stscBadAttachmentS = 'Attachment Doesn''t Exist'; + stscDupeStringS = 'Duplicate string'; + stscInStreamS = 'Error in input stream'; + + stscOutOfBoundsS = 'Index out of string bounds'; + + stscInvalidLengthS = 'POSTNET code must be 5, 9 or 11 digits'; + + + stscNoInputFileS = 'Input file not specified'; + stscNoOutputFileS = 'Output file not specified'; + stscInFileErrorS = 'Error opening input file'; + stscOutFileErrorS = 'Error creating output file'; + + + stscNameS = 'Name'; + stscSizeS = 'Size'; + stscTypeS = 'Type'; + stscModifiedS = 'Modified'; + stscAttributesS = 'Attributes'; + stscFileFolderS = 'File Folder'; + stscSystemFolderS = 'System Folder'; + stscOriginalLocS = 'Original Location'; + stscDateDeletedS = 'Date Deleted'; + stscFileS = 'File'; + stscInvalidFolderS = 'Invalid folder'; + stscFolderReadOnlyS = 'Cannot create folder: Parent folder is read-only'; + stscInvalidSortDirS = 'Invalid sort direction'; + + stscInsufficientDataS = 'FileName cannot be empty when RunParameters is specified'; + + stscCreateFileFailedS = 'CreateFile failed'; + stscFileMappingFailedS = 'CreateFileMapping failed'; + stscCreateViewFailedS = 'MapViewOfFile failed'; + stscBadOriginS = 'Bad origin parameter for call to Seek'; + stscGetSizeFailedS = 'Error reading size of existing file'; + + stscNilStreamS = 'Buffered/text stream: Attempted to read, write, or seek and underlying stream is nil'; + stscNoSeekForReadS = 'Buffered/text stream: Could not seek to the correct position in the underlying stream (for read request)'; + stscNoSeekForWriteS = 'Buffered/text stream: Could not seek to the correct position in the underlying stream (for write request)'; + stscCannotWriteS = 'Buffered/text stream: Could not write the entire buffer to the underlying stream'; + stscBadTerminatorS = 'Text stream: Case statement was used with a bad value of LineTerminator'; + stscBadLineLengthS = 'Text stream: Length of a fixed line must be between 1 and 4096 bytes'; + stscCannotSetSizeS = 'Buffered/text stream: Cannot set the size of the underlying stream (needs OnSetStreamSize event)'; + + stscUnknownErrorS = 'Unknown error creating a pattern token'; + stscExpandingClassS = 'Problem in expanding character class'; + stscAlternationFollowsClosureS = 'Alternation cannot immediately follow a closure marker'; + stscUnbalancedParensS = 'Unbalanced nesting parentheses'; + stscFollowingClosureS = 'Closure cannot immediately follow BegOfLine, EndOfLine or another closure'; + stscPatternErrorS = 'Error detected near end of pattern'; + stscUnbalancedTagS = 'Unbalanced tag marker'; + stscNoPatternsS = 'No Match, Replace, or SelAvoid Patterns defined'; + stscPatternTooLargeS = 'Pattern exceeds MaxPatLen'; + stscStreamsNilS = 'Input and/or output stream is not assigned'; + stscInTextStreamErrorS = 'Error creating internal input text stream'; + stscOutTextStreamErrorS = 'Error creating internal output text stream'; + stscClosureMaybeEmptyS = 'A * or + operand could be empty'; + stscOutFileDeleteS = 'Error deleting old previous file'; + stscInFileNotFoundS = 'Input file not found'; + stscREInFileErrorS = 'Error creating internal text stream'; + stscOutFileCreateS = 'Error creating output file'; + + + stscNetNoManualCreateS = 'Can''t manually create an object of this type'; + stscNetUnknownErrorS = 'Unknown network error'; + stscNetGroupNotSpecifiedS = 'Local or global group not specified'; + stscNetDateSpecifiedOutOfRangeS = 'Date specified out or range'; + stscNetInvalidParameterS = 'Invalid parameter'; + stscNetInvalidItemTypeS = 'Invalid item type for this method'; + + stscStatBadCountS = 'Unequal or bad counts of array elements'; + stscStatBadParamS = 'Invalid parameter'; + stscStatBadDataS = 'Invalid data point in array'; + stscStatNoConvergeS = 'no convergence in numerical routine'; + + stscWordDelimitersS = '219'; + stscInvalidSLEntryS = '220'; + stscBadStreamS = '221'; + + stscMoneyIdxOutOfRangeS = 'Index out of range (%s)'; + stscMoneyNilResultS = 'Nil result parameter'; + stscMoneyNilParameterS = 'Nil parameter to operation'; + stscMoneyCurrenciesNotMatchS = 'Currencies do not match'; + stscMoneyNoExchangeRatesAvailS = 'No Exchange Rates Available'; + stscMoneyInvalidExchangeParamsS = 'Invalid exchange parameters'; + stscMoneyInvalidTriangleExchangeS = 'Invalid triangle exchange'; + stscMoneyNoSuchExchangeS = 'No exchange rate for %s->%s available'; + stscMoneyMissingIntermediateRateS = 'Intermediate exchange rate for %s->%s missing'; + stscMoneyInvalidExchRateS = 'Exchange rate is missing a property value'; + stscMoneyTriExchUsesTriExchS = 'Triangular exchange rate is using triangular exchange rates'; + + stscDecMathRoundPlacesS = 'Decimal math: the number of decimal places to round to must be betwen 0 and 16'; + stscDecMathAsIntOverflowS = 'Decimal math: current value overflows an integer'; + stscDecMathConversionS = 'Decimal math: string value not a valid number'; + stscDecMathDivByZeroS = 'Decimal math: division by zero attempted'; + stscDecMathNegExpS = 'Decimal math: cannot raise to a negative power'; + stscDecMathMultOverflowS = 'Decimal math: result overflowed during multiplication'; + stscDecMathDivOverflowS = 'Decimal math: result overflowed during division'; + + stscTxtDatNoSuchFieldS = 'No such field'; + stscTxtDatUniqueNameRequiredS = 'Field name must be unique'; + stscTxtDatUnhandledVariantS = 'Unhandled Variant Type'; + stscTxtDatInvalidSchemaS = 'Invalid Schema'; + stscTxtDatRecordSetOpenS = 'Cannot perform this operation on an open record set'; + + stscPRNGDegFreedomS = 'StRandom: the number of degrees of freedom should be greater than zero'; + stscPRNGBetaShapeS = 'StRandom: the Beta distribution shape values should be greater than zero'; + stscPRNGMeanS = 'StRandom: the mean must be greater than zero'; + stscPRNGGammaShapeS = 'StRandom: the Gamma distribution shape must be greater than zero'; + stscPRNGGammaScaleS = 'StRandom: the Gamma distribution scale must be greater than zero'; + stscPRNGStdDevS = 'StRandom: the standard deviation must be greater than zero'; + stscPRNGWeibullShapeS = 'StRandom: the Weibull distribution shape must be greater than zero'; + stscPRNGWeibullScaleS = 'StRandom: the Weibull distribution scale must be greater than zero'; + stscPRNGLimitS = 'StRandom: the limit must be greater than zero'; + stscPRNGUpperLimitS = 'StRandom: the upper limit must be greater than the lower limit'; + stscPRNGErlangOrderS = 'StRandom: the Erlang distribution''s order must be greater than zero'; + + +type + StStrRec = record + ID: Integer; + Str: string; + end; + +const + SysToolsStrArray : array [0..174] of StStrRec = ( + + {string table constants for STREGINI} + (ID: stscFalseString; Str: stscFalseStringS), + (ID: stscTrueString; Str: stscTrueStringS), + (ID: stscNoFileKey; Str: stscNoFileKeyS), + (ID: stscInvalidPKey; Str: stscInvalidPKeyS), + (ID: stscNoWin32S; Str: stscNoWin32SS), + (ID: stscCreateKeyFail; Str: stscCreateKeyFailS), + (ID: stscOpenKeyFail; Str: stscOpenKeyFailS), + (ID: stscIniWriteFail; Str: stscIniWriteFailS), + (ID: stscRegWriteFail; Str: stscRegWriteFailS), + (ID: stscNoKeyName; Str: stscNoKeyNameS), + (ID: stscQueryKeyFail; Str: stscQueryKeyFailS), + (ID: stscEnumKeyFail; Str: stscEnumKeyFailS), + (ID: stscEnumValueFail; Str: stscEnumValueFailS), + (ID: stscIniDeleteFail; Str: stscIniDeleteFailS), + (ID: stscKeyHasSubKeys; Str: stscKeyHasSubKeysS), + (ID: stscDeleteKeyFail; Str: stscDeleteKeyFailS), + (ID: stscIniDelValueFail; Str: stscIniDelValueFailS), + (ID: stscRegDelValueFail; Str: stscRegDelValueFailS), + (ID: stscOutputFileExists; Str: stscOutputFileExistsS), + (ID: stscFileHasExtension; Str: stscFileHasExtensionS), + (ID: stscSaveKeyFail; Str: stscSaveKeyFailS), + (ID: stscNo16bitSupport; Str: stscNo16bitSupportS), + (ID: stscCantFindInputFile; Str: stscCantFindInputFileS), + (ID: stscLoadKeyFail; Str: stscLoadKeyFailS), + (ID: stscUnloadKeyFail; Str: stscUnloadKeyFailS), + (ID: stscNotWinNTPlatform; Str: stscNotWinNTPlatformS), + (ID: stscBadOptionsKeyCombo; Str: stscBadOptionsKeyComboS), + (ID: stscRestoreKeyFail; Str: stscRestoreKeyFailS), + (ID: stscReplaceKeyFail; Str: stscReplaceKeyFailS), + (ID: stscNoIniFileSupport; Str: stscNoIniFileSupportS), + (ID: stscRemoteKeyIsOpen; Str: stscRemoteKeyIsOpenS), + (ID: stscConnectRemoteKeyFail; Str: stscConnectRemoteKeyFailS), + (ID: stscCloseRemoteKeyFail; Str: stscCloseRemoteKeyFailS), + (ID: stscFlushKeyFail; Str: stscFlushKeyFailS), + (ID: stscBufferDataSizesDif; Str: stscBufferDataSizesDifS), + (ID: stscKeyIsEmptyNotExists; Str: stscKeyIsEmptyNotExistsS), + (ID: stscGetSecurityFail; Str: stscGetSecurityFailS), + (ID: stscSetSecurityFail; Str: stscSetSecurityFailS), + (ID: stscByteArrayTooLarge; Str: stscByteArrayTooLargeS), + (ID: stscQueryValueFail; Str: stscQueryValueFailS), + (ID: stscNoValueNameSpecified; Str: stscNoValueNameSpecifiedS), + + {string table constants for container classes} + (ID: stscNoCompare; Str: stscNoCompareS), {Compare property must be set} + (ID: stscBadType; Str: stscBadTypeS), {an incompatible class is passed to a method} + (ID: stscBadSize; Str: stscBadSizeS), {bad size for TStDictionary, TStBits, TStCollection} + (ID: stscDupNode; Str: stscDupNodeS), {attempt to add duplicate node to TStTree} + (ID: stscBadIndex; Str: stscBadIndexS), {bad index passed to TStBits or large array} + (ID: stscBadWinMode; Str: stscBadWinModeS), {requires enhanced mode operation} + (ID: stscUnknownClass; Str: stscUnknownClassS), {container class name not registered} + (ID: stscUnknownNodeClass; Str: stscUnknownNodeClassS), {container node class name not registered} + (ID: stscNoStoreData; Str: stscNoStoreDataS), {container has no store data routine} + (ID: stscNoLoadData; Str: stscNoLoadDataS), {container has no load data routine} + (ID: stscWrongClass; Str: stscWrongClassS), {container class and streamed class not equal} + (ID: stscWrongNodeClass; Str: stscWrongNodeClassS), {container node class and streamed class not equal} + (ID: stscBadCompare; Str: stscBadCompareS), {invalid compare function or unable to assign now} + (ID: stscTooManyCols; Str: stscTooManyColsS), {assign a matrix with >1 col to array} + (ID: stscBadColCount; Str: stscBadColCountS), {assign a matrix with wrong col count to virtual matrix} + (ID: stscBadElSize; Str: stscBadElSizeS), {assign a matrix with wrong elem size to virtual matrix} + (ID: stscBadDups; Str: stscBadDupsS), {setting Dups to False in a non-empty sorted collection} + + {string table constants for sorting unit} + (ID: stscTooManyFiles; Str: stscTooManyFilesS), {too many merge files in TStSorter} + (ID: stscFileCreate; Str: stscFileCreateS), {error creating file in TStSorter} + (ID: stscFileOpen; Str: stscFileOpenS), {error opening file in TStSorter} + (ID: stscFileWrite; Str: stscFileWriteS), {error writing file in TStSorter} + (ID: stscFileRead; Str: stscFileReadS), {error reading file in TStSorter} + (ID: stscBadState; Str: stscBadStateS), {TStSorter in wrong state} + + {string table constants for Bcd unit} + (ID: stscBcdBadFormat; Str: stscBcdBadFormatS), {bad BCD format} + (ID: stscBcdOverflow; Str: stscBcdOverflowS), {BCD larger than 10**64} + (ID: stscBcdDivByZero; Str: stscBcdDivByZeroS), {BCD divide by zero} + (ID: stscBcdBadInput; Str: stscBcdBadInputS), {BCD negative input to sqrt, ln, or power} + (ID: stscBcdBufOverflow; Str: stscBcdBufOverflowS), {buffer overflow in FormatBcd} + (ID: stscNoVerInfo; Str: stscNoVerInfoS), {no version info in file} + (ID: stscVerInfoFail; Str: stscVerInfoFailS), {error reading version info} + +(* + {shell string constants} + (ID: stscShellVersionError; Str: stscShellVersionErrorS), {not available in this version of Shell32.dll} + (ID: stscShellFileOpSrcError; Str: stscShellFileOpSrcErrorS), {no source files specified} + (ID: stscShellFileOpDstError; Str: stscShellFileOpDstErrorS), {no destination files specified} + (ID: stscShellFileOpMapError; Str: stscShellFileOpMapErrorS), {mapping incomplete} + (ID: stscShellFormatError; Str: stscShellFormatErrorS), {format error} + (ID: stscShellFormatCancel; Str: stscShellFormatCancelS), {format cancelled} + (ID: stscShellFormatNoFormat; Str: stscShellFormatNoFormatS), {drive cannot be formatted} + (ID: stscShellFormatBadDrive; Str: stscShellFormatBadDriveS), {not removable drive} + (ID: stscTrayIconInvalidOS; Str: stscTrayIconInvalidOSS), {bad OS (NT 3.51)} + (ID: stscTrayIconCantAdd; Str: stscTrayIconCantAddS), {can't add icon to the tray} + (ID: stscTrayIconCantDelete; Str: stscTrayIconCantDeleteS), {can't delete icon from the tray} + (ID: stscTrayIconError; Str: stscTrayIconErrorS), {general tray icon error} + (ID: stscBadDropTarget; Str: stscBadDropTargetS), {drop target is not TWinControl} + (ID: stscCOMInitFailed; Str: stscCOMInitFailedS), {COInitialize failed} + (ID: stscNoPathSpecified; Str: stscNoPathSpecifiedS), {No destination path for shortcut} + (ID: stscIShellLinkError; Str: stscIShellLinkErrorS), {Error creating IShellLink} + (ID: stscNotShortcut; Str: stscNotShortcutS), {File is not a shortcut} + (ID: stscTrayIconClose; Str: stscTrayIconCloseS), {Close} + (ID: stscTrayIconRestore; Str: stscTrayIconRestoreS), {Restore} + (ID: stscInvalidTargetFile; Str: stscInvalidTargetFileS), {Shortcut target file not found} + (ID: stscShellFileOpDelete; Str: stscShellFileOpDeleteS), {Can't use file mappings with delete op} + (ID: stscShellFileNotFound; Str: stscShellFileNotFoundS), {One or more source files is missing} + (ID: stscTrayIconDuplicate; Str: stscTrayIconDuplicateS), {Cant' have more than one tray icon} + (ID: stscBadVerInfoKey; Str: stscBadVerInfoKeyS), {User-defined key not found in ver info} + (ID: stscImageListInvalid; Str: stscImageListInvalidS), {No image list assigned.} +*) + (ID: stscBadVerInfoKey; Str: stscBadVerInfoKeyS), {User-defined key not found in ver info} + + {barcode errors} + (ID: stscInvalidUPCACodeLen; Str: stscInvalidUPCACodeLenS), + (ID: stscInvalidCharacter; Str: stscInvalidCharacterS), + (ID: stscInvalidCheckCharacter; Str: stscInvalidCheckCharacterS), + (ID: stscInvalidUPCECodeLen; Str: stscInvalidUPCECodeLenS), + (ID: stscInvalidEAN8CodeLen; Str: stscInvalidEAN8CodeLenS), + (ID: stscInvalidEAN13CodeLen; Str: stscInvalidEAN13CodeLenS), + (ID: stscInvalidSupCodeLen; Str: stscInvalidSupCodeLenS), + + {stexpr errors} + (ID: stscExprEmpty; Str: stscExprEmptyS), {empty expression} + (ID: stscExprBadNum; Str: stscExprBadNumS), {error in floating point number} + (ID: stscExprBadChar; Str: stscExprBadCharS), {unknown character} + (ID: stscExprOpndExp; Str: stscExprOpndExpS), {expected function, number, sign, or (} + (ID: stscExprNumeric; Str: stscExprNumericS), {numeric error} + (ID: stscExprBadExp; Str: stscExprBadExpS), {invalid expression} + (ID: stscExprOpndOvfl; Str: stscExprOpndOvflS), {operand stack overflow} + (ID: stscExprUnkFunc; Str: stscExprUnkFuncS), {unknown function identifier} + (ID: stscExprLParExp; Str: stscExprLParExpS), {left parenthesis expected} + (ID: stscExprRParExp; Str: stscExprRParExpS), {right parenthesis expected} + (ID: stscExprCommExp; Str: stscExprCommExpS), {list separator (comma) expected} + (ID: stscExprDupIdent; Str: stscExprDupIdentS), {duplicate identifier} + + {ststat errors} + (ID: stscStatBadCount; Str: stscStatBadCountS), {unequal or bad counts of array elements} + (ID: stscStatBadParam; Str: stscStatBadParamS), {invalid parameter} + (ID: stscStatBadData; Str: stscStatBadDataS), {invalid data point in array} + (ID: stscStatNoConverge; Str: stscStatNoConvergeS), {no convergence in numerical routine} + + {stfin errors} + (ID: stscFinBadArg; Str: stscFinBadArgS), + (ID: stscFinNoConverge; Str: stscFinNoConvergeS), + + {stmime errors} + (ID: stscBadEncodeFmt; Str: stscBadEncodeFmtS), + (ID: stscBadAttachment; Str: stscBadAttachmentS), + (ID: stscDupeString; Str: stscDupeStringS), + (ID: stscInStream; Str: stscInStreamS), + + {ststring errors} + (ID: stscOutOfBounds; Str: stscOutOfBoundsS), {Index out of string bounds} + + + {stBarPN errors} + (ID: stscInvalidLength; Str: stscInvalidLengthS), + + {StHTML errors} + (ID: stscNoInputFile; Str: stscNoInputFileS), + (ID: stscNoOutputFile; Str: stscNoOutputFileS), + (ID: stscInFileError; Str: stscInFileErrorS), + (ID: stscOutFileError; Str: stscOutFileErrorS), + (ID: stscWordDelimiters; Str: stscWordDelimitersS), + (ID: stscInvalidSLEntry; Str: stscInvalidSLEntryS), + (ID: stscBadStream; Str: stscBadStreamS), + + {StShlCtl constansts} + (ID: stscName; Str: stscNameS), + (ID: stscSize; Str: stscSizeS), + (ID: stscType; Str: stscTypeS), + (ID: stscModified; Str: stscModifiedS), + (ID: stscAttributes; Str: stscAttributesS), + (ID: stscFileFolder; Str: stscFileFolderS), + (ID: stscSystemFolder; Str: stscSystemFolderS), + (ID: stscOriginalLoc; Str: stscOriginalLocS), + (ID: stscDateDeleted; Str: stscDateDeletedS), + (ID: stscFile; Str: stscFileS), + (ID: stscInvalidFolder; Str: stscInvalidFolderS), + (ID: stscFolderReadOnly; Str: stscFolderReadOnlyS), + + {StSpawnApplication errors} + (ID: stscInsufficientData; Str: stscInsufficientDataS), + + {StMemoryMappedFile errors} + (ID: stscCreateFileFailed; Str: stscCreateFileFailedS), + (ID: stscFileMappingFailed; Str: stscFileMappingFailedS), + (ID: stscCreateViewFailed; Str: stscCreateViewFailedS), + (ID: stscBadOrigin; Str: stscBadOriginS), + (ID: stscGetSizeFailed; Str: stscGetSizeFailedS), + + {buffered stream errors} + (ID: stscNilStream; Str: stscNilStreamS), + (ID: stscNoSeekForRead; Str: stscNoSeekForReadS), + (ID: stscNoSeekForWrite; Str: stscNoSeekForWriteS), + (ID: stscCannotWrite; Str: stscCannotWriteS), + (ID: stscBadTerminator; Str: stscBadTerminatorS), + (ID: stscBadLineLength; Str: stscBadLineLengthS), + (ID: stscCannotSetSize; Str: stscCannotSetSizeS), + + {RegEx errors} + (ID: stscUnknownError; Str: stscUnknownErrorS), + (ID: stscExpandingClass; Str: stscExpandingClassS), + (ID: stscAlternationFollowsClosure; Str: stscAlternationFollowsClosureS), + (ID: stscUnbalancedParens; Str: stscUnbalancedParensS), + (ID: stscFollowingClosure; Str: stscFollowingClosureS), + (ID: stscPatternError; Str: stscPatternErrorS), + (ID: stscUnbalancedTag; Str: stscUnbalancedTagS), + (ID: stscNoPatterns; Str: stscNoPatternsS), + (ID: stscPatternTooLarge; Str: stscPatternTooLargeS), + (ID: stscStreamsNil; Str: stscStreamsNilS), + (ID: stscInTextStreamError; Str: stscInTextStreamErrorS), + (ID: stscOutTextStreamError; Str: stscOutTextStreamErrorS), + (ID: stscClosureMaybeEmpty; Str: stscClosureMaybeEmptyS), + (ID: stscInFileNotFound; Str: stscInFileNotFoundS), + (ID: stscREInFileError; Str: stscREInFileErrorS), + (ID: stscOutFileDelete; Str: stscOutFileDeleteS), + (ID: stscOutFileCreate; Str: stscOutFileCreateS), + + + {StNet errors 320-339} + (ID: stscNetNoManualCreate; Str: stscNetNoManualCreateS), + (ID: stscNetUnknownError; Str: stscNetUnknownErrorS), + (ID: stscNetGroupNotSpecified; Str: stscNetGroupNotSpecifiedS), + (ID: stscNetDateSpecifiedOutOfRange; Str: stscNetDateSpecifiedOutOfRangeS), + (ID: stscNetInvalidParameter; Str: stscNetInvalidParameterS), + (ID: stscNetInvalidItemType; Str: stscNetInvalidItemTypeS), + + { StMoney errors } +// (ID: stscMoneyIdxOutOfRange; Str: stscMoneyIdxOutOfRangeS), + (ID: stscMoneyNilResult; Str: stscMoneyNilResultS), + (ID: stscMoneyNilParameter; Str: stscMoneyNilParameterS), + (ID: stscMoneyCurrenciesNotMatch; Str: stscMoneyCurrenciesNotMatchS), + (ID: stscMoneyNoExchangeRatesAvail; Str: stscMoneyNoExchangeRatesAvailS), + (ID: stscMoneyInvalidExchangeParams; Str: stscMoneyInvalidExchangeParamsS), + (ID: stscMoneyInvalidTriangleExchange; Str: stscMoneyInvalidTriangleExchangeS), + (ID: stscMoneyNoSuchExchange; Str: stscMoneyNoSuchExchangeS), + (ID: stscMoneyMissingIntermediateRate; Str: stscMoneyMissingIntermediateRateS), + (ID: stscMoneyInvalidExchRate; Str: stscMoneyInvalidExchRateS), + (ID: stscMoneyTriExchUsesTriExch; Str: stscMoneyTriExchUsesTriExchS), + (ID: stscDecMathMultOverflow; Str: stscDecMathMultOverflowS), + (ID: stscDecMathDivOverflow; Str: stscDecMathDivOverflowS), + + (ID: stscTxtDatNoSuchField; Str: stscTxtDatNoSuchFieldS), + (ID: stscTxtDatUniqueNameRequired; Str: stscTxtDatUniqueNameRequiredS), + (ID: stscTxtDatUnhandledVariant; Str: stscTxtDatUnhandledVariantS), + (ID: stscTxtDatInvalidSchema; Str: stscTxtDatInvalidSchemaS), + (ID: stscTxtDatRecordSetOpen; Str: stscTxtDatRecordSetOpenS) + ); + +function SysToolsStr(Index : Integer) : string; + +implementation + +function SysToolsStr(Index : Integer) : string; +var + i : Integer; +begin + for i := Low(SysToolsStrArray) to High(SysToolsStrArray) do + if SysToolsStrArray[i].ID = Index then + Result := SysToolsStrArray[i].Str; +end; + + +initialization + +end. diff --git a/components/systools/source/run/stcrc.pas b/components/systools/source/run/stcrc.pas new file mode 100644 index 000000000..9751b8fee --- /dev/null +++ b/components/systools/source/run/stcrc.pas @@ -0,0 +1,382 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StCRC.pas 4.04 *} +{*********************************************************} +{* SysTools: Cyclic redundancy check unit for SysTools *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} +{ +Note: CRC routines rely on overflows for their results, +so these need to be off: +} +{$R-} +{$Q-} + +unit StCRC; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils, Classes, + StBase; + +const + CrcBufSize = 2048; + CrcFileMode = fmOpenRead or fmShareDenyWrite; + +function Adler32Prim(var Data; DataSize : Cardinal; CurCrc : LongInt) : LongInt; +function Adler32OfStream(Stream : TStream; CurCrc : LongInt) : LongInt; +function Adler32OfFile(FileName : String) : LongInt; + +function Crc16Prim(var Data; DataSize, CurCrc : Cardinal) : Cardinal; +function Crc16OfStream(Stream : TStream; CurCrc : Cardinal) : Cardinal; +function Crc16OfFile(FileName : String) : Cardinal; + +function Crc32Prim(var Data; DataSize : Cardinal; CurCrc : LongInt) : LongInt; +function Crc32OfStream(Stream : TStream; CurCrc : LongInt) : LongInt; +function Crc32OfFile(FileName : String) : LongInt; + +function InternetSumPrim(var Data; DataSize, CurCrc : Cardinal) : Cardinal; +function InternetSumOfStream(Stream : TStream; CurCrc : Cardinal) : Cardinal; +function InternetSumOfFile(FileName : String) : Cardinal; + +function Kermit16Prim(var Data; DataSize, CurCrc : Cardinal) : Cardinal; +function Kermit16OfStream(Stream : TStream; CurCrc : Cardinal) : Cardinal; +function Kermit16OfFile(FileName : String) : Cardinal; + +const + { Cardinal takes more space, but is about 10% faster in 32-bit } + CrcTable: array[0..255] of Cardinal = ( + $0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7, + $8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef, + $1231, $0210, $3273, $2252, $52b5, $4294, $72f7, $62d6, + $9339, $8318, $b37b, $a35a, $d3bd, $c39c, $f3ff, $e3de, + $2462, $3443, $0420, $1401, $64e6, $74c7, $44a4, $5485, + $a56a, $b54b, $8528, $9509, $e5ee, $f5cf, $c5ac, $d58d, + $3653, $2672, $1611, $0630, $76d7, $66f6, $5695, $46b4, + $b75b, $a77a, $9719, $8738, $f7df, $e7fe, $d79d, $c7bc, + $48c4, $58e5, $6886, $78a7, $0840, $1861, $2802, $3823, + $c9cc, $d9ed, $e98e, $f9af, $8948, $9969, $a90a, $b92b, + $5af5, $4ad4, $7ab7, $6a96, $1a71, $0a50, $3a33, $2a12, + $dbfd, $cbdc, $fbbf, $eb9e, $9b79, $8b58, $bb3b, $ab1a, + $6ca6, $7c87, $4ce4, $5cc5, $2c22, $3c03, $0c60, $1c41, + $edae, $fd8f, $cdec, $ddcd, $ad2a, $bd0b, $8d68, $9d49, + $7e97, $6eb6, $5ed5, $4ef4, $3e13, $2e32, $1e51, $0e70, + $ff9f, $efbe, $dfdd, $cffc, $bf1b, $af3a, $9f59, $8f78, + $9188, $81a9, $b1ca, $a1eb, $d10c, $c12d, $f14e, $e16f, + $1080, $00a1, $30c2, $20e3, $5004, $4025, $7046, $6067, + $83b9, $9398, $a3fb, $b3da, $c33d, $d31c, $e37f, $f35e, + $02b1, $1290, $22f3, $32d2, $4235, $5214, $6277, $7256, + $b5ea, $a5cb, $95a8, $8589, $f56e, $e54f, $d52c, $c50d, + $34e2, $24c3, $14a0, $0481, $7466, $6447, $5424, $4405, + $a7db, $b7fa, $8799, $97b8, $e75f, $f77e, $c71d, $d73c, + $26d3, $36f2, $0691, $16b0, $6657, $7676, $4615, $5634, + $d94c, $c96d, $f90e, $e92f, $99c8, $89e9, $b98a, $a9ab, + $5844, $4865, $7806, $6827, $18c0, $08e1, $3882, $28a3, + $cb7d, $db5c, $eb3f, $fb1e, $8bf9, $9bd8, $abbb, $bb9a, + $4a75, $5a54, $6a37, $7a16, $0af1, $1ad0, $2ab3, $3a92, + $fd2e, $ed0f, $dd6c, $cd4d, $bdaa, $ad8b, $9de8, $8dc9, + $7c26, $6c07, $5c64, $4c45, $3ca2, $2c83, $1ce0, $0cc1, + $ef1f, $ff3e, $cf5d, $df7c, $af9b, $bfba, $8fd9, $9ff8, + $6e17, $7e36, $4e55, $5e74, $2e93, $3eb2, $0ed1, $1ef0 + ); + +const + Crc32Table : array[0..255] of DWORD = ( + $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, + $9e6495a3, $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, + $e7b82d07, $90bf1d91, $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, + $6ddde4eb, $f4d4b551, $83d385c7, $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, + $14015c4f, $63066cd9, $fa0f3d63, $8d080df5, $3b6e20c8, $4c69105e, $d56041e4, + $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b, $35b5a8fa, $42b2986c, + $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59, $26d930ac, + $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f, + $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, + $b6662d3d, $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, + $9fbfe4a5, $e8b8d433, $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, + $086d3d2d, $91646c97, $e6635c01, $6b6b51f4, $1c6c6162, $856530d8, $f262004e, + $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457, $65b0d9c6, $12b7e950, $8bbeb8ea, + $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65, $4db26158, $3ab551ce, + $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb, $4369e96a, + $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9, + $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, + $ce61e49f, $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, + $b7bd5c3b, $c0ba6cad, $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, + $9dd277af, $04db2615, $73dc1683, $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, + $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1, $f00f9344, $8708a3d2, $1e01f268, + $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7, $fed41b76, $89d32be0, + $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5, $d6d6a3e8, + $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b, + $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, + $4669be79, $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, + $220216b9, $5505262f, $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, + $b5d0cf31, $2cd99e8b, $5bdeae1d, $9b64c2b0, $ec63f226, $756aa39c, $026d930a, + $9c0906a9, $eb0e363f, $72076785, $05005713, $95bf4a82, $e2b87a14, $7bb12bae, + $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21, $86d3d2d4, $f1d4e242, + $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777, $88085ae6, + $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45, + $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, + $3e6e77db, $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, + $47b2cf7f, $30b5ffe9, $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, + $cdd70693, $54de5729, $23d967bf, $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, + $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d + ); + +implementation + +{$IFDEF TRIALRUN} +uses + StTrial; +{$ENDIF} + +type + CRCByteArray = array[0..Pred(High(LongInt))] of Byte; + +function Adler32Prim(var Data; DataSize : Cardinal; CurCrc : LongInt) : LongInt; + { Calculates the Adler 32-bit CRC of a block } +var + S1, S2, I : LongInt; +begin + if DataSize > 0 then begin + S1 := CurCrc and $FFFF; + S2 := (CurCrc shr 16) and $FFFF; + + for I := 0 to (DataSize-1) do begin + S1 := (S1 + CRCByteArray(Data)[I]) mod 65521; + S2 := (S2 + S1) mod 65521; + end; + + Result := (S2 shl 16) + S1; + end else + Result := CurCrc; +end; + +function Adler32OfStream(Stream : TStream; CurCrc : LongInt) : LongInt; + { Calculates the Adler 32-bit CRC of a stream } +var + BufArray : array[0..(CrcBufSize-1)] of Byte; + Res : LongInt; +begin + {Initialize Crc} + Result := CurCrc; + repeat + Res := Stream.Read(BufArray, CrcBufSize); + Result := Adler32Prim(BufArray, Res, Result); + until (Res <> CrcBufSize); +end; + +function Adler32OfFile(FileName : String) : LongInt; + { Calculates the Adler 32-bit CRC of a file } +var + FileSt : TFileStream; +begin + FileSt := TFileStream.Create(FileName, CrcFileMode); + try + Result := Adler32OfStream(FileSt, 1); + finally + FileSt.Free; + end; +end; + +function Crc16Prim(var Data; DataSize, CurCrc : Cardinal) : Cardinal; + { Calculates the 16-bit CRC of a block } +var + I : Integer; +begin + Result := CurCrc; + for I := 0 to (DataSize-1) do + Result := (CrcTable[((Result shr 8) and 255)] xor (Result shl 8) xor + CRCByteArray(Data)[I]) and $FFFF; +end; + +function Crc16OfStream(Stream : TStream; CurCrc : Cardinal) : Cardinal; + { Calculates the 16-bit CRC of a stream } +var + BufArray : array[0..(CrcBufSize-1)] of Byte; + Res : LongInt; +begin + {Initialize Crc} + Result := CurCrc; + repeat + Res := Stream.Read(BufArray, CrcBufSize); + Result := Crc16Prim(BufArray, Res, Result); + until (Res <> CrcBufSize); +end; + +function Crc16OfFile(FileName : String) : Cardinal; + { Calculates the 16-bit CRC of a file } +var + FileSt : TFileStream; +begin + FileSt := TFileStream.Create(FileName, CrcFileMode); + try + Result := Crc16OfStream(FileSt, 0); + finally + FileSt.Free; + end; +end; + +function Crc32Prim(var Data; DataSize : Cardinal; CurCrc : LongInt) : LongInt; + { Calculates the 32-bit CRC of a block } +var + I : Integer; +begin + Result := CurCrc; + for I := 0 to (DataSize-1) do + Result := Crc32Table[Byte(Result xor CRCByteArray(Data)[I])] xor + DWord((Result shr 8) and $00FFFFFF); +end; + +function Crc32OfStream(Stream : TStream; CurCrc : LongInt) : LongInt; + { Calculates the 32-bit CRC of a stream } +var + BufArray : array[0..(CrcBufSize-1)] of Byte; + Res : LongInt; +begin + {Initialize Crc} + Result := CurCrc; + repeat + Res := Stream.Read(BufArray, CrcBufSize); + Result := Crc32Prim(BufArray, Res, Result); + until (Res <> CrcBufSize); +end; + +function Crc32OfFile(FileName : String) : LongInt; + { Calculates the 32-bit CRC of a file } +var + FileSt : TFileStream; +begin + FileSt := TFileStream.Create(FileName, CrcFileMode); + try + Result := not Crc32OfStream(FileSt, LongInt($FFFFFFFF)); + finally + FileSt.Free; + end; +end; + +function InternetSumPrim(var Data; DataSize, CurCrc : Cardinal) : Cardinal; + { Calculates the Internet Checksum of a block } +var + I : Integer; +begin + Result := CurCrc; + if DataSize = 0 then Exit; + for I := 0 to (DataSize - 1) do begin + if Odd(I) then + Result := Result + (CRCByteArray(Data)[I] shl 8) + else + Result := Result + CRCByteArray(Data)[I]; + end; + Result := (not((Result and $FFFF) + (Result shr 16))) and $FFFF; +end; + +function InternetSumOfStream(Stream : TStream; CurCrc : Cardinal) : Cardinal; + { Calculates the Internet Checksum of a stream } +var + BufArray : array[0..(CrcBufSize-1)] of Byte; + Res : LongInt; +begin + {Initialize Crc} + Result := CurCrc; + repeat + Res := Stream.Read(BufArray, CrcBufSize); + Result := InternetSumPrim(BufArray, Res, Result); + until (Res <> CrcBufSize); +end; + +function InternetSumOfFile(FileName : String) : Cardinal; + { Calculates the Internet Checksum of a file } +var + FileSt : TFileStream; +begin + FileSt := TFileStream.Create(FileName, CrcFileMode); + try + Result := InternetSumOfStream(FileSt, 0); + finally + FileSt.Free; + end; +end; + +function Kermit16Prim(var Data; DataSize, CurCrc : Cardinal) : Cardinal; + { Calculates the Kermit 16-bit CRC of a block } +var + I, J : Integer; + Temp : Cardinal; + CurrByte : Byte; +begin + for I := 0 to (DataSize-1) do begin + CurrByte := CRCByteArray(Data)[I]; + for J := 0 to 7 do begin + Temp := CurCrc xor CurrByte; + CurCrc := CurCrc shr 1; + if Odd(Temp) then + CurCrc := CurCrc xor $8408; + CurrByte := CurrByte shr 1; + end; + end; + Result := CurCrc; +end; + +function Kermit16OfStream(Stream : TStream; CurCrc : Cardinal) : Cardinal; + { Calculates the Kermit 16-bit CRC of a stream } +var + BufArray : array[0..(CrcBufSize-1)] of Byte; + Res : LongInt; +begin + {Initialize Crc} + Result := CurCrc; + repeat + Res := Stream.Read(BufArray, CrcBufSize); + Result := Kermit16Prim(BufArray, Res, Result); + until (Res <> CrcBufSize); +end; + +function Kermit16OfFile(FileName : String) : Cardinal; + { Calculates the Kermit 16-bit CRC of a file } +var + FileSt : TFileStream; +begin + FileSt := TFileStream.Create(FileName, CrcFileMode); + try + Result := Kermit16OfStream(FileSt, 0); + finally + FileSt.Free; + end; +end; + + +end. diff --git a/components/systools/source/run/stdate.pas b/components/systools/source/run/stdate.pas new file mode 100644 index 000000000..af095c194 --- /dev/null +++ b/components/systools/source/run/stdate.pas @@ -0,0 +1,965 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDate.pas 4.04 *} +{*********************************************************} +{* SysTools: Date and time manipulation *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} +//{$I StDefine.inc} + +{For BCB 3.0 package support.} +{$IFDEF VER110} + {$ObjExportAll On} +{$ENDIF} + +unit StDate; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils; + +type + TStDate = LongInt; + {In STDATE, dates are stored in long integer format as the number of days + since January 1, 1600} + + TDateArray = array[0..(MaxLongInt div SizeOf(TStDate))-1] of TStDate; + {Type for StDate open array} + + TStDayType = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday); + {An enumerated type used when representing a day of the week} + + TStBondDateType = (bdtActual, bdt30E360, bdt30360, bdt30360psa); + {An enumerated type used for calculating bond date differences} + + TStTime = LongInt; + {STDATE handles time in a manner similar to dates, representing a given + time of day as the number of seconds since midnight} + + TStDateTimeRec = + record + {This record type simply combines the two basic date types defined by + STDATE, Date and Time} + D : TStDate; + T : TStTime; + end; + +const + MinYear = 1600; {Minimum valid year for a date variable} + MaxYear = 3999; {Maximum valid year for a date variable} + Mindate = $00000000; {Minimum valid date for a date variable - 01/01/1600} + Maxdate = $000D6025; {Maximum valid date for a date variable - 12/31/3999} + Date1900 : longint = $0001AC05; {Julian date for 01/01/1900} + Date1970 : longint = $00020FE4; {Julian date for 01/01/1970} + Date1980 : longint = $00021E28; {Julian date for 01/01/1980} + Date2000 : longint = $00023AB1; {Julian date for 01/01/2000} + Days400Yr : longint = 146097; {days in 400 years} + {This value is used to represent an invalid date, such as 12/32/1992} + BadDate = LongInt($FFFFFFFF); + + DeltaJD = $00232DA8; {Days between 1/1/-4173 and 1/1/1600} + + MinTime = 0; {Minimum valid time for a time variable - 00:00:00 am} + MaxTime = 86399; {Maximum valid time for a time variable - 23:59:59 pm} + {This value is used to represent an invalid time of day, such as 12:61:00} + BadTime = LongInt($FFFFFFFF); + SecondsInDay = 86400; {Number of seconds in a day} + SecondsInHour = 3600; {Number of seconds in an hour} + SecondsInMinute = 60; {Number of seconds in a minute} + HoursInDay = 24; {Number of hours in a day} + MinutesInHour = 60; {Number of minutes in an hour} + MinutesInDay = 1440; {Number of minutes in a day} + +var + DefaultYear : Integer; {default year--used by DateStringToDMY} + DefaultMonth : ShortInt; {default month} + + {-------julian date routines---------------} + +function CurrentDate : TStDate; + {-returns today's date as a Julian date} + +function ValidDate(Day, Month, Year, Epoch : Integer) : Boolean; + {-Verify that day, month, year is a valid date} + +function DMYtoStDate(Day, Month, Year, Epoch : Integer) : TStDate; + {-Convert from day, month, year to a Julian date} + +procedure StDateToDMY(Julian : TStDate; var Day, Month, Year : Integer); + {-Convert from a Julian date to day, month, year} + +function IncDate(Julian : TStDate; Days, Months, Years : Integer) : TStDate; + {-Add (or subtract) the number of days, months, and years to a date} + +function IncDateTrunc(Julian : TStDate; Months, Years : Integer) : TStDate; + {-Add (or subtract) the specified number of months and years to a date} + +procedure DateDiff(Date1, Date2 : TStDate; + var Days, Months, Years : Integer); +{-Return the difference in days, months, and years between two valid Julian + dates} + +function BondDateDiff(Date1, Date2 : TStDate; DayBasis : TStBondDateType) : TStDate; + {-Return the difference in days between two valid Julian + dates using a specific financial basis} + +function WeekOfYear(Julian : TStDate) : Byte; + {-Returns the week number of the year given the Julian Date} + +function AstJulianDate(Julian : TStDate) : Double; + {-Returns the Astronomical Julian Date from a TStDate} + +function AstJulianDatetoStDate(AstJulian : Double; Truncate : Boolean) : TStDate; + {-Returns a TStDate from an Astronomical Julian Date. + Truncate TRUE Converts to appropriate 0 hours then truncates + FALSE Converts to appropriate 0 hours, then rounds to + nearest;} + +function AstJulianDatePrim(Year, Month, Date : Integer; UT : TStTime) : Double; + {-Returns an Astronomical Julian Date for any year, even those outside + MinYear..MaxYear} + +function DayOfWeek(Julian : TStDate) : TStDayType; + {-Return the day of the week for a Julian date} + +function DayOfWeekDMY(Day, Month, Year, Epoch : Integer) : TStDayType; + {-Return the day of the week for the day, month, year} + +function IsLeapYear(Year : Integer) : Boolean; + {-Return True if Year is a leap year} + +function DaysInMonth(Month : Integer; Year, Epoch : Integer) : Integer; + {-Return the number of days in the specified month of a given year} + +function ResolveEpoch(Year, Epoch : Integer) : Integer; + {-Convert 2 digit year to 4 digit year according to Epoch} + + + {-------time routines---------------} + +function ValidTime(Hours, Minutes, Seconds : Integer) : Boolean; + {-Return True if Hours:Minutes:Seconds is a valid time} + +procedure StTimeToHMS(T : TStTime; + var Hours, Minutes, Seconds : Byte); + {-Convert a time variable to hours, minutes, seconds} + +function HMStoStTime(Hours, Minutes, Seconds : Byte) : TStTime; + {-Convert hours, minutes, seconds to a time variable} + +function CurrentTime : TStTime; + {-Return the current time in seconds since midnight} + +procedure TimeDiff(Time1, Time2 : TStTime; + var Hours, Minutes, Seconds : Byte); + {-Return the difference in hours, minutes, and seconds between two times} + +function IncTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime; + {-Add the specified hours, minutes, and seconds to a given time of day} + +function DecTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime; + {-Subtract the specified hours, minutes, and seconds from a given time of day} + +function RoundToNearestHour(T : TStTime; Truncate : Boolean) : TStTime; + {-Given a time, round it to the nearest hour, or truncate minutes and + seconds} + +function RoundToNearestMinute(const T : TStTime; Truncate : Boolean) : TStTime; + {-Given a time, round it to the nearest minute, or truncate seconds} + + {-------- routines for DateTimeRec records ---------} + +procedure DateTimeDiff(const DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec; {!!.02} + var Days : LongInt; var Secs : LongInt); + {-Return the difference in days and seconds between two points in time} + +procedure IncDateTime(const DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec; {!!.02} + Days : Integer; Secs : LongInt); + {-Increment (or decrement) a date and time by the specified number of days + and seconds} + +function DateTimeToStDate(DT : TDateTime) : TStDate; + {-Convert Delphi TDateTime to TStDate} + +function DateTimeToStTime(DT : TDateTime) : TStTime; + {-Convert Delphi TDateTime to TStTime} + +function StDateToDateTime(D : TStDate) : TDateTime; + {-Convert TStDate to TDateTime} + +function StTimeToDateTime(T : TStTime) : TDateTime; + {-Convert TStTime to TDateTime} + +function Convert2ByteDate(TwoByteDate : Word) : TStDate; + {-Convert an Object Professional two byte date into a SysTools date} + +function Convert4ByteDate(FourByteDate : TStDate) : Word; + {-Convert a SysTools date into an Object Professional two byte date} + + +implementation + +const + First2Months = 59; {1600 was a leap year} + FirstDayOfWeek = Saturday; {01/01/1600 was a Saturday} + DateLen = 40; {maximum length of Picture strings} + MaxMonthName = 15; + MaxDayName = 15; + + +//type +{ DateString = string[DateLen];} +// SString = string[255]; + +function IsLeapYear(Year : Integer) : Boolean; + {-Return True if Year is a leap year} +begin + Result := (Year mod 4 = 0) and (Year mod 4000 <> 0) and + ((Year mod 100 <> 0) or (Year mod 400 = 0)); +end; + +function IsLastDayofMonth(Day, Month, Year : Integer) : Boolean; + {-Return True if date is the last day in month} +var + Epoch : Integer; +begin + Epoch := (Year div 100) * 100; + if ValidDate(Day + 1, Month, Year, Epoch) then + Result := false + else + Result := true; +end; + +function IsLastDayofFeb(Date : TStDate) : Boolean; + {-Return True if date is the last day in February} +var + Day, Month, Year : Integer; +begin + StDateToDMY(Date, Day, Month, Year); + if (Month = 2) and IsLastDayOfMonth(Day, Month, Year) then + Result := true + else + Result := false; +end; + +procedure ExchangeLongInts(var I, J : LongInt); +register; +asm + mov ecx, [eax] + push ecx + mov ecx, [edx] + mov [eax], ecx + pop ecx + mov [edx], ecx +end; + +procedure ExchangeStructs(var I, J; Size : Cardinal); +register; +asm + push edi + push ebx + push ecx + shr ecx, 2 + jz @@LessThanFour + +@@AgainDWords: + mov ebx, [eax] + mov edi, [edx] + mov [edx], ebx + mov [eax], edi + add eax, 4 + add edx, 4 + dec ecx + jnz @@AgainDWords + +@@LessThanFour: + pop ecx + and ecx, $3 + jz @@Done + mov bl, [eax] + mov bh, [edx] + mov [edx], bl + mov [eax], bh + inc eax + inc edx + dec ecx + jz @@Done + + mov bl, [eax] + mov bh, [edx] + mov [edx], bl + mov [eax], bh + inc eax + inc edx + dec ecx + jz @@Done + + mov bl, [eax] + mov bh, [edx] + mov [edx], bl + mov [eax], bh + +@@Done: + pop ebx + pop edi +end; + + +function ResolveEpoch(Year, Epoch : Integer) : Integer; + {-Convert 2-digit year to 4-digit year according to Epoch} +var + EpochYear, + EpochCent : Integer; +begin + if Word(Year) < 100 then begin + EpochYear := Epoch mod 100; + EpochCent := (Epoch div 100) * 100; + if (Year < EpochYear) then + Inc(Year,EpochCent+100) + else + Inc(Year,EpochCent); + end; + Result := Year; +end; + +function CurrentDate : TStDate; + {-Returns today's date as a julian} +var + Year, Month, Date : Word; +begin + DecodeDate(Now,Year,Month,Date); + Result := DMYToStDate(Date,Month,Year,0); +end; + +function DaysInMonth(Month : integer; Year, Epoch : Integer) : Integer; + {-Return the number of days in the specified month of a given year} +begin + Year := ResolveEpoch(Year, Epoch); + + if (Year < MinYear) OR (Year > MaxYear) then + begin + Result := 0; + Exit; + end; + + case Month of + 1, 3, 5, 7, 8, 10, 12 : + Result := 31; + 4, 6, 9, 11 : + Result := 30; + 2 : + Result := 28+Ord(IsLeapYear(Year)); + else + Result := 0; + end; +end; + +function ValidDate(Day, Month, Year, Epoch : Integer) : Boolean; + {-Verify that day, month, year is a valid date} +begin + Year := ResolveEpoch(Year, Epoch); + + if (Day < 1) or (Year < MinYear) or (Year > MaxYear) then + Result := False + else case Month of + 1..12 : + Result := Day <= DaysInMonth(Month, Year, Epoch); + else + Result := False; + end +end; + +function DMYtoStDate(Day, Month, Year, Epoch : Integer) : TStDate; + {-Convert from day, month, year to a julian date} +begin + Year := ResolveEpoch(Year, Epoch); + + if not ValidDate(Day, Month, Year, Epoch) then + Result := BadDate + else if (Year = MinYear) and (Month < 3) then + if Month = 1 then + Result := Pred(Day) + else + Result := Day+30 + else begin + if Month > 2 then + Dec(Month, 3) + else begin + Inc(Month, 9); + Dec(Year); + end; + Dec(Year, MinYear); + Result := + ((LongInt(Year div 100)*Days400Yr) div 4)+ + ((LongInt(Year mod 100)*1461) div 4)+ + (((153*Month)+2) div 5)+Day+First2Months; + end; +end; + +function WeekOfYear(Julian : TStDate) : Byte; + {-Returns the week number of the year given the Julian Date} +var + Day, Month, Year : Integer; + FirstJulian : TStDate; +begin + if (Julian < MinDate) or (Julian > MaxDate) then + begin + Result := 0; + Exit; + end; + + Julian := Julian + 3 - ((6 + Ord(DayOfWeek(Julian))) mod 7); + StDateToDMY(Julian,Day,Month,Year); + FirstJulian := DMYToStDate(1,1,Year,0); + Result := 1 + (Julian - FirstJulian) div 7; +end; + +function AstJulianDate(Julian : TStDate) : Double; + {-Returns the Astronomical Julian Date from a TStDate} +begin + {Subtract 0.5d since Astronomical JD starts at noon + while TStDate (with implied .0) starts at midnight} + Result := Julian - 0.5 + DeltaJD; +end; + + +function AstJulianDatePrim(Year, Month, Date : Integer; UT : TStTime) : Double; +var + A, B : integer; + LY, + GC : Boolean; + +begin + Result := -MaxLongInt; + if (not (Month in [1..12])) or (Date < 1) then + Exit + else if (Month in [1, 3, 5, 7, 8, 10, 12]) and (Date > 31) then + Exit + else if (Month in [4, 6, 9, 11]) and (Date > 30) then + Exit + else if (Month = 2) then begin + LY := IsLeapYear(Year); + if ((LY) and (Date > 29)) or (not (LY) and (Date > 28)) then + Exit; + end else if ((UT < 0) or (UT >= SecondsInDay)) then + Exit; + + if (Month <= 2) then begin + Year := Year - 1; + Month := Month + 12; + end; + A := abs(Year div 100); + + if (Year > 1582) then + GC := True + else if (Year = 1582) then begin + if (Month > 10) then + GC := True + else if (Month < 10) then + GC := False + else begin + if (Date >= 15) then + GC := True + else + GC := False; + end; + end else + GC := False; + if (GC) then + B := 2 - A + abs(A div 4) + else + B := 0; + + Result := Trunc(365.25 * (Year + 4716)) + + Trunc(30.6001 * (Month + 1)) + + Date + B - 1524.5 + + UT / SecondsInDay; +end; + + +function AstJulianDatetoStDate(AstJulian : Double; Truncate : Boolean) : TStDate; + {-Returns a TStDate from an Astronomical Julian Date. + Truncate TRUE Converts to appropriate 0 hours then truncates + FALSE Converts to appropriate 0 hours, then rounds to + nearest;} +begin + {Convert to TStDate, adding 0.5d for implied .0d of TStDate} + AstJulian := AstJulian + 0.5 - DeltaJD; + if (AstJulian < MinDate) OR (AstJulian > MaxDate) then + begin + Result := BadDate; + Exit; + end; + + if Truncate then + Result := Trunc(AstJulian) + else + Result := Trunc(AstJulian + 0.5); +end; + +procedure StDateToDMY(Julian : TStDate; var Day, Month, Year : Integer); + {-Convert from a julian date to month, day, year} +var + I, J : LongInt; +begin + if Julian = BadDate then begin + Day := 0; + Month := 0; + Year := 0; + end else if Julian <= First2Months then begin + Year := MinYear; + if Julian <= 30 then begin + Month := 1; + Day := Succ(Julian); + end else begin + Month := 2; + Day := Julian-30; + end; + end else begin + I := (4*LongInt(Julian-First2Months))-1; + + J := (4*((I mod Days400Yr) div 4))+3; + Year := (100*(I div Days400Yr))+(J div 1461); + I := (5*(((J mod 1461)+4) div 4))-3; + Day := ((I mod 153)+5) div 5; + + Month := I div 153; + if Month < 10 then + Inc(Month, 3) + else begin + Dec(Month, 9); + Inc(Year); + end; + Inc(Year, MinYear); + end; +end; + +function IncDate(Julian : TStDate; Days, Months, Years : Integer) : TStDate; + {-Add (or subtract) the number of months, days, and years to a date. + Months and years are added before days. No overflow/underflow + checks are made} +var + Day, Month, Year, Day28Delta : Integer; +begin + StDateToDMY(Julian, Day, Month, Year); + Day28Delta := Day-28; + if Day28Delta < 0 then + Day28Delta := 0 + else + Day := 28; + + Inc(Year, Years); + Inc(Year, Months div 12); + Inc(Month, Months mod 12); + if Month < 1 then begin + Inc(Month, 12); + Dec(Year); + end + else if Month > 12 then begin + Dec(Month, 12); + Inc(Year); + end; + + Julian := DMYtoStDate(Day, Month, Year,0); + if Julian <> BadDate then begin + Inc(Julian, Days); + Inc(Julian, Day28Delta); + end; + Result := Julian; +end; + +function IncDateTrunc(Julian : TStDate; Months, Years : Integer) : TStDate; + {-Add (or subtract) the specified number of months and years to a date} +var + Day, Month, Year : Integer; + MaxDay, Day28Delta : Integer; +begin + StDateToDMY(Julian, Day, Month, Year); + Day28Delta := Day-28; + if Day28Delta < 0 then + Day28Delta := 0 + else + Day := 28; + + Inc(Year, Years); + Inc(Year, Months div 12); + Inc(Month, Months mod 12); + if Month < 1 then begin + Inc(Month, 12); + Dec(Year); + end + else if Month > 12 then begin + Dec(Month, 12); + Inc(Year); + end; + + Julian := DMYtoStDate(Day, Month, Year,0); + if Julian <> BadDate then begin + MaxDay := DaysInMonth(Month, Year,0); + if Day+Day28Delta > MaxDay then + Inc(Julian, MaxDay-Day) + else + Inc(Julian, Day28Delta); + end; + Result := Julian; +end; + +procedure DateDiff(Date1, Date2 : TStDate; var Days, Months, Years : Integer); + {-Return the difference in days,months,years between two valid julian dates} +var + Day1, Day2, Month1, Month2, Year1, Year2 : Integer; +begin + {we want Date2 > Date1} + if Date1 > Date2 then + ExchangeLongInts(Date1, Date2); + + {convert dates to day,month,year} + StDateToDMY(Date1, Day1, Month1, Year1); + StDateToDMY(Date2, Day2, Month2, Year2); + + {days first} + if (Day1 = DaysInMonth(Month1, Year1, 0)) then begin + Day1 := 0; + Inc(Month1); {OK if Month1 > 12} + end; + if (Day2 = DaysInMonth(Month2, Year2, 0)) then begin + Day2 := 0; + Inc(Month2); {OK if Month2 > 12} + end; + if (Day2 < Day1) then begin + Dec(Month2); + if Month2 = 0 then begin + Month2 := 12; + Dec(Year2); + end; + Days := Day2 + DaysInMonth(Month2, Year2, 0) - Day1; {!!.02} + end else + Days := Day2-Day1; + + {now months and years} + if Month2 < Month1 then begin + Inc(Month2, 12); + Dec(Year2); + end; + Months := Month2-Month1; + Years := Year2-Year1; +end; + +function BondDateDiff(Date1, Date2 : TStDate; DayBasis : TStBondDateType) : TStDate; + {-Return the difference in days between two valid Julian + dates using one a specific accrual method} +var + Day1, + Month1, + Year1, + Day2, + Month2, + Year2 : Integer; + IY : LongInt; +begin + {we want Date2 > Date1} + if Date1 > Date2 then + ExchangeLongInts(Date1, Date2); + + if (DayBasis = bdtActual) then + Result := Date2-Date1 + else + begin + StDateToDMY(Date1, Day1, Month1, Year1); + StDateToDMY(Date2, Day2, Month2, Year2); + + if ((DayBasis = bdt30360PSA) and IsLastDayofFeb(Date1)) or (Day1 = 31) then + Day1 := 30; + if (DayBasis = bdt30E360) then + begin + if (Day2 = 31) then + Day2 := 30 + end else + if (Day2 = 31) and (Day1 >= 30) then + Day2 := 30; + + IY := 360 * (Year2 - Year1); + Result := IY + 30 * (Month2 - Month1) + (Day2 - Day1); + end; +end; + +function DayOfWeek(Julian : TStDate) : TStDayType; + {-Return the day of the week for the date. Returns TStDayType(7) if Julian = + BadDate.} +var + B : Byte; +begin + if Julian = BadDate then begin + B := 7; + Result := TStDayType(B); + end else + Result := TStDayType( (Julian+Ord(FirstDayOfWeek)) mod 7 ); +end; + +function DayOfWeekDMY(Day, Month, Year, Epoch : Integer) : TStDayType; + {-Return the day of the week for the day, month, year} +begin + Result := DayOfWeek( DMYtoStDate(Day, Month, Year, Epoch) ); +end; + +procedure StTimeToHMS(T : TStTime; var Hours, Minutes, Seconds : Byte); + {-Convert a Time variable to Hours, Minutes, Seconds} +begin + if T = BadTime then begin + Hours := 0; + Minutes := 0; + Seconds := 0; + end + else begin + Hours := T div SecondsInHour; + Dec(T, LongInt(Hours)*SecondsInHour); + Minutes := T div SecondsInMinute; + Dec(T, LongInt(Minutes)*SecondsInMinute); + Seconds := T; + end; +end; + +function HMStoStTime(Hours, Minutes, Seconds : Byte) : TStTime; + {-Convert Hours, Minutes, Seconds to a Time variable} +var + T : TStTime; +begin + Hours := Hours mod HoursInDay; + T := (LongInt(Hours)*SecondsInHour)+(LongInt(Minutes)*SecondsInMinute)+Seconds; + Result := T mod SecondsInDay; +end; + +function ValidTime(Hours, Minutes, Seconds : Integer) : Boolean; + {-Return true if Hours:Minutes:Seconds is a valid time} +begin + if (Hours < 0) or (Hours > 23) or + (Minutes < 0) or (Minutes >= 60) or + (Seconds < 0) or (Seconds >= 60) then + Result := False + else + Result := True; +end; + +function CurrentTime : TStTime; + {-Returns current time in seconds since midnight} +begin + Result := Trunc(SysUtils.Time * SecondsInDay); +end; + +procedure TimeDiff(Time1, Time2 : TStTime; var Hours, Minutes, Seconds : Byte); + {-Return the difference in hours,minutes,seconds between two times} +begin + StTimeToHMS(Abs(Time1-Time2), Hours, Minutes, Seconds); +end; + +function IncTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime; + {-Add the specified hours,minutes,seconds to T and return the result} +begin + Inc(T, HMStoStTime(Hours, Minutes, Seconds)); + Result := T mod SecondsInDay; +end; + +function DecTime(T : TStTime; Hours, Minutes, Seconds : Byte) : TStTime; + {-Subtract the specified hours,minutes,seconds from T and return the result} +begin + Hours := Hours mod HoursInDay; + Dec(T, HMStoStTime(Hours, Minutes, Seconds)); + if T < 0 then + Result := T+SecondsInDay + else + Result := T; +end; + +function RoundToNearestHour(T : TStTime; Truncate : Boolean) : TStTime; + {-Round T to the nearest hour, or Truncate minutes and seconds from T} +var + Hours, Minutes, Seconds : Byte; +begin + StTimeToHMS(T, Hours, Minutes, Seconds); + Seconds := 0; + if not Truncate then + if Minutes >= (MinutesInHour div 2) then + Inc(Hours); + Minutes := 0; + Result := HMStoStTime(Hours, Minutes, Seconds); +end; + +function RoundToNearestMinute(const T : TStTime; Truncate : Boolean) : TStTime; + {-Round T to the nearest minute, or Truncate seconds from T} +var + Hours, Minutes, Seconds : Byte; +begin + StTimeToHMS(T, Hours, Minutes, Seconds); + if not Truncate then + if Seconds >= (SecondsInMinute div 2) then + Inc(Minutes); + Seconds := 0; + Result := HMStoStTime(Hours, Minutes, Seconds); +end; + + +procedure DateTimeDiff(const DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec; {!!.02} + var Days : LongInt; var Secs : LongInt); + {-Return the difference in days and seconds between two points in time} +var + tDT1, tDT2 : TStDateTimeRec; +begin + tDT1 := DT1; + tDT2 := DT2; + {swap if tDT1 later than tDT2} + if (tDT1.D > tDT2.D) or ((tDT1.D = tDT2.D) and (tDT1.T > tDT2.T)) then + ExchangeStructs(tDT1, tDT2,sizeof(TStDateTimeRec)); + + {the difference in days is easy} + Days := tDT2.D-tDT1.D; + + {difference in seconds} + if tDT2.T < tDT1.T then begin + {subtract one day, add 24 hours} + Dec(Days); + Inc(tDT2.T, SecondsInDay); + end; + Secs := tDT2.T-tDT1.T; +end; + +function DateTimeToStDate(DT : TDateTime) : TStDate; + {-Convert Delphi TDateTime to TStDate} +var + Day, Month, Year : Word; +begin + DecodeDate(DT, Year, Month, Day); + Result := DMYToStDate(Day, Month, Year, 0); +end; + +function DateTimeToStTime(DT : TDateTime) : TStTime; + {-Convert Delphi TDateTime to TStTime} +var + Hour, Min, Sec, MSec : Word; +begin + DecodeTime(DT, Hour, Min, Sec, MSec); + Result := HMSToStTime(Hour, Min, Sec); +end; + +function StDateToDateTime(D : TStDate) : TDateTime; + {-Convert TStDate to TDateTime} +var + Day, Month, Year : Integer; +begin + Result := 0; + if D <> BadDate then begin + StDateToDMY(D, Day, Month, Year); + Result := EncodeDate(Year, Month, Day); + end; +end; + +function StTimeToDateTime(T : TStTime) : TDateTime; + {-Convert TStTime to TDateTime} +var + Hour, Min, Sec : Byte; +begin + Result := 0; + if T <> BadTime then begin + StTimeToHMS(T, Hour, Min, Sec); + Result := EncodeTime(Hour, Min, Sec, 0); + end; +end; + +procedure IncDateTime(const DT1 : TStDateTimeRec; var DT2 : TStDateTimeRec; {!!.02} + Days : Integer; Secs : LongInt); + {-Increment (or decrement) DT1 by the specified number of days and seconds + and put the result in DT2} +begin + DT2 := DT1; + + {date first} + Inc(DT2.D, LongInt(Days)); + + if Secs < 0 then begin + {change the sign} + Secs := -Secs; + + {adjust the date} + Dec(DT2.D, Secs div SecondsInDay); + Secs := Secs mod SecondsInDay; + + if Secs > DT2.T then begin + {subtract a day from DT2.D and add a day's worth of seconds to DT2.T} + Dec(DT2.D); + Inc(DT2.T, SecondsInDay); + end; + + {now subtract the seconds} + Dec(DT2.T, Secs); + end + else begin + {increment the seconds} + Inc(DT2.T, Secs); + + {adjust date if necessary} + Inc(DT2.D, DT2.T div SecondsInDay); + + {force time to 0..SecondsInDay-1 range} + DT2.T := DT2.T mod SecondsInDay; + end; +end; + +function Convert2ByteDate(TwoByteDate : Word) : TStDate; +begin + Result := LongInt(TwoByteDate) + Date1900; +end; + +function Convert4ByteDate(FourByteDate : TStDate) : Word; +begin + Result := Word(FourByteDate - Date1900); +end; + +procedure SetDefaultYear; + {-Initialize DefaultYear and DefaultMonth} +var + Month, Day, Year : Word; + T : TDateTime; +begin + T := Now; + DecodeDate(T, Year, Month, Day); + DefaultYear := Year; + DefaultMonth := Month; +end; + + +initialization + {initialize DefaultYear and DefaultMonth} + SetDefaultYear; +end. diff --git a/components/systools/source/run/stdatest.pas b/components/systools/source/run/stdatest.pas new file mode 100644 index 000000000..7cb0b6ffe --- /dev/null +++ b/components/systools/source/run/stdatest.pas @@ -0,0 +1,1111 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDateSt.pas 4.04 *} +{*********************************************************} +{* SysTools: Date and time string manipulation *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +{$I StDefine.inc} + +unit StDateSt; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils, + StStrS, + StStrL, + StConst, + StBase, + StUtils, + StDate; + +const + {the following characters are meaningful in date Picture strings} + MonthOnly = 'm'; {Formatting character for a date string picture mask} + DayOnly = 'd'; {Formatting character for a date string picture mask} + YearOnly = 'y'; {Formatting character for a date string picture mask} + MonthOnlyU = 'M'; {Formatting character for a date string picture mask. + Uppercase means pad with ' ' rather than '0'} + DayOnlyU = 'D'; {Formatting character for a date string picture mask. + Uppercase means pad with ' ' rather then '0'} + DateSlash = '/'; {Formatting character for a date string picture mask} + + {'n'/'N' may be used in place of 'm'/'M' when the name of the month is + desired instead of its number. E.g., 'dd/nnn/yyyy' -\> '01-Jan-1980'. + 'dd/NNN/yyyy' -\> '01-JAN-1980' (if SlashChar = '-'). The abbreviation used + is based on the width of the subfield (3 in the example) and the current + contents of the MonthString array.} + NameOnly = 'n'; {Formatting character for a date string picture mask} + NameOnlyU = 'N'; {Formatting character for a date string picture mask. + Uppercase causes the output to be in uppercase} + + {'w'/'W' may be used to include the day of the week in a date string. E.g., + 'www dd nnn yyyy' -\> 'Mon 01 Jan 1989'. The abbreviation used is based on + the width of the subfield (3 in the example) and the current contents of the + DayString array. Note that TurboPower Entry Fields will not allow the user to + enter text into a subfield containing 'w' or 'W'. The day of the week will be + supplied automatically when a valid date is entered.} + WeekDayOnly = 'w'; {Formatting character for a date string picture mask} + WeekDayOnlyU = 'W'; {Formatting character for a date string picture mask. + Uppercase causes the output to be in uppercase} + + LongDateSub1 = 'f'; {Mask character used strictly for dealing with Window's + long date format} + LongDateSub2 = 'g'; {Mask character used strictly for dealing with Window's + long date format} + LongDateSub3 = 'h'; {Mask character used strictly for dealing with Window's + long date format} + + HourOnly = 'h'; {Formatting character for a time string picture mask} + MinOnly = 'm'; {Formatting character for a time string picture mask} + SecOnly = 's'; {Formatting character for a time string picture mask} + {if uppercase letters are used, numbers are padded with ' ' rather than '0'} + HourOnlyU = 'H'; {Formatting character for a time string picture mask. + Uppercase means pad with ' ' rather than '0'} + MinOnlyU = 'M'; {Formatting character for a time string picture mask. + Uppercase means pad with ' ' rather than '0'} + SecOnlyU = 'S'; {Formatting character for a time string picture mask. + Uppercase means pad with ' ' rather than '0'} + {'hh:mm:ss tt' -\> '12:00:00 pm', 'hh:mmt' -\> '12:00p'} + TimeOnly = 't'; {Formatting character for a time string picture mask. + This generates 'AM' or 'PM'} + TimeColon = ':'; {Formatting character for a time string picture mask} + + + {-------julian date routines---------------} + +function DateStringHMStoAstJD(const Picture, DS : string; {!!.02} + H,M,S,Epoch : integer) : Double; + {-Returns the Astronomical Julian Date using a Date String, + Hours, Minutes, Seconds} + +function MonthToString(const Month : Integer) : string; + {-Return the month as a string} + + {-------date string routines---------------} + +function DateStringToStDate(const Picture, S : string; Epoch : Integer) : TStDate; + {-Convert a string to a Julian date} + +function DateStringToDMY(const Picture, S : string; + Epoch : Integer; + var D, M, Y : Integer) : Boolean; + {-Extract day, month, and year from a date string} + +function StDateToDateString(const Picture : string; const Julian : TStDate; + Pack : Boolean) : string; + {-Convert a Julian date to a string} + +function DayOfWeekToString(const WeekDay : TStDayType) : string; + {-Return the day of the week specified by WeekDay as a string in Dest.} + +function DMYtoDateString(const Picture : string; + Day, Month, Year, Epoch : Integer; + Pack : Boolean) : string; + {-Merge the month, day, and year into the picture} + +function CurrentDateString(const Picture : string; Pack : Boolean) : string; + {-Return today's date as a string} + + {-------time routines---------------} + +function CurrentTimeString(const Picture : string; + Pack : Boolean) : string; + {-Return the current time as a string of the specified form} + +function TimeStringToHMS(const Picture, St : string; + var H, M, S : Integer) : Boolean; + {-Extract hours, minutes, seconds from a time string} + +function TimeStringToStTime(const Picture, S : string) : TStTime; + {-Convert a time string to a time variable} + +function StTimeToAmPmString(const Picture : string; + const T : TStTime; Pack : Boolean) : string; + {-Convert a time variable to a time string in am/pm format} + +function StTimeToTimeString(const Picture : string; const T : TStTime; + Pack : Boolean) : string; + {-Convert a time variable to a time string} + + + {-------- routines for international date/time strings ---------} + +function DateStringIsBlank(const Picture, S : string) : Boolean; + {-Return True if the month, day, and year in S are all blank} + +function InternationalDate(ForceCentury : Boolean) : string; + {-Return a picture mask for a short date string, based on Windows' international + information} + +function InternationalLongDate(ShortNames : Boolean; + ExcludeDOW : Boolean) : string; + {-Return a picture mask for a date string, based on Windows' international + information} + +function InternationalTime(ShowSeconds : Boolean) : string; + {-Return a picture mask for a time string, based on Windows' international + information} + +procedure ResetInternationalInfo; + {-Update internal info to match Windows' international info} + + +implementation + +const + First2Months = 59; {1600 was a leap year} + FirstDayOfWeek = Saturday; {01/01/1600 was a Saturday} + DateLen = 40; {maximum length of Picture strings} + MaxMonthName = 15; + MaxDayName = 15; + +//type +{ DateString = string[DateLen];} +// SString = string[255]; + +var + wLongDate : string;//[40]; + wldSub1 : string[6]; //SZ: careful if converting to string; some code depends on sizeof (search for [*] around line 1021) + wldSub2 : string[6]; + wldSub3 : string[6]; + wShortDate : string;//[31]; + w1159 : string[7]; + w2359 : string[7]; + wSlashChar : Char; + wColonChar : Char; + wTLZero : Boolean; + w12Hour : Boolean; + DefaultYear : Integer; {default year--used by DateStringToDMY} + DefaultMonth : ShortInt; {default month} + + procedure ExtractFromPicture(const Picture, S : string; Ch : Char; {!!.02} + var I : Integer; Blank, Default : Integer); forward; + + procedure AppendChar(var S : String; Ch : Char); + begin + SetLength(S,Succ(Length(S))); + S[Length(S)] := Ch; + end; + + function DayOfWeekToString(const WeekDay : TStDayType) : string; + {-Return the day of the week specified by WeekDay as a string in Dest. + Will honor international names} + begin + Result := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongDayNames[Ord(WeekDay)+1]; + end; + + function MonthToString(const Month : Integer) : string; + {-Return the month as a string. Will honor international names} + begin + if (Month >= 1) and (Month <= 12) then + Result := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongMonthNames[Month] + else + Result := ''; + end; + + function AstJulianDatePrim(Year,Month,Date : Integer) : Double; + var + A, B : integer; + begin + if Month <= 2 then {!!.01} + begin + Dec(Year); + Inc(Month,12); + end; + A := Trunc(Year/100); + B := 2 - A + Trunc(A/4); + + Result := Trunc(365.25 * (Year+4716)) + + Trunc(30.6001 * (Month+1)) + + Date + B - 1524.5; + end; + + function DateStringHMSToAstJD(const Picture, DS : string; {!!.02} + H,M,S,Epoch : Integer) : Double; + {-Returns the Astronomical Julian Date using a Date String, + Hours, Minutes, Seconds} + var + Date, Month, Year : Integer; + begin + ExtractFromPicture(Picture, DS, NameOnly, Month, -1, 0); + if Month = 0 then + ExtractFromPicture(Picture, DS, MonthOnly, Month, -1, DefaultMonth); + ExtractFromPicture(Picture, DS, DayOnly, Date, -1, 1); + ExtractFromPicture(Picture, DS, YearOnly, Year, -1, DefaultYear); + + Year := ResolveEpoch(Year, Epoch); + Result := AstJulianDatePrim(Year,Month,Date) + + H/HoursInDay + M/MinutesInDay + S/SecondsInDay; + end; + + function MonthStringToMonth(const MSt : string; Width : Byte) : Byte;{!!.02} + {-Convert the month name in MSt to a month (1..12)} + var + S : String; + T : String; + Len : Byte; + I : Word; + begin + S := UpperCase(MSt); + Len := Length(S); +// SetLength(S,Width); +// if Width > Len then +// FillChar(S[Len+1], Length(S)-Len, ' '); + S := S + StringOfChar(' ', Width - Len); + + for I := 1 to 12 do begin + T := UpperCase({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongMonthNames[I]); + Len := Length(T); +// SetLength(T,Width); +// if Width > Len then +// FillChar(T[Len+1], Length(T)-Len, ' '); + T := T + StringOfChar(' ', Width - Len); + + if S = T then begin + Result := I; + Exit; + end; + end; + Result := 0; + end; + + procedure ExtractFromPicture(const Picture, S : string; Ch : Char; {!!.02} + var I : Integer; Blank, Default : Integer); + {-Extract the value of the subfield specified by Ch from S and return in + I. I will be set to -1 in case of an error, Blank if the subfield exists + in Picture but is empty, Default if the subfield doesn't exist in + Picture.} + var + PTmp : string; + C, posLCCh, posUCCh : Cardinal; + Code : Integer; + begin + {find the start of the subfield} + I := Default; + + StrChPosL(Picture, Ch, posLCCh); + Ch := StBase.Upcase(Ch); + StrChPosL(Picture, Ch, posUCCh); + + if (posLCCh < 1) or ((posUCCh > 0) and (posUCCh < posLCCh)) then + posLCCh := posUCCh; + if (posLCCh < 1) or (Length(S) <> Length(Picture)) then + Exit; + + {extract the substring} + + PTmp := ''; + C := Length(Picture); + while (posLCCh <= C) and (StBase.Upcase(Picture[posLCCh]) = Ch) do begin + if S[posLCCh] <> ' ' then + AppendChar(PTmp,Char(S[posLCCh])); + Inc(posLCCh); + end; + + if Length(PTmp) = 0 then + I := Blank + else if Ch = NameOnlyU then begin + I := MonthStringToMonth(PTmp, Length(PTmp)); + if I = 0 then + I := -1; + end + else begin + {convert to a value} + Val(PTmp, I, Code); + if Code <> 0 then + I := -1; + end; + end; + + function DateStringToDMY(const Picture, S : string; + Epoch : Integer; + var D, M, Y : Integer) : Boolean; + {-Extract day, month, and year from S, returning true if string is valid} + begin + ExtractFromPicture(Picture, S, NameOnly, M, -1, 0); + if M = 0 then + ExtractFromPicture(Picture, S, MonthOnly, M, -1, DefaultMonth); + ExtractFromPicture(Picture, S, DayOnly, D, -1, 1); + ExtractFromPicture(Picture, S, YearOnly, Y, -1, DefaultYear); + if ValidDate(D, M, Y, Epoch) then begin + Result := True; + Y := ResolveEpoch(Y, Epoch); + end else + Result := False; + end; + + function DateStringIsBlank(const Picture, S : string) : Boolean; + {-Return True if the month, day, and year in S are all blank} + var + M, D, Y : Integer; + begin + ExtractFromPicture(Picture, S, NameOnly, M, -2, 0); + if M = 0 then + ExtractFromPicture(Picture, S, MonthOnly, M, -2, -2); + ExtractFromPicture(Picture, S, DayOnly, D, -2, -2); + ExtractFromPicture(Picture, S, YearOnly, Y, -2, -2); + Result := (M = -2) and (D = -2) and (Y = -2); + end; + + + function DateStringToStDate(const Picture, S : string; Epoch : Integer) : TStDate; + {-Convert S, a string of the form indicated by Picture, to a julian date. + Picture and S must be of equal lengths} + var + Month, Day, Year : Integer; + begin + {extract day, month, year from S} + if DateStringToDMY(Picture, S, Epoch, Day, Month, Year) then + {convert to julian date} + Result := DMYtoStDate(Day, Month, Year, Epoch) + else + Result := BadDate; + end; + + function SubstCharSim(P : string; OC, NC : Char) : string; + var + step : integer; + begin + for step := 1 to Length(P) do + begin + if P[step] = OC then + P[step] := NC; + end; + Result := P; + end; + + function SubstChar(Picture : string; OldCh, NewCh : Char) : string; + {-Replace all instances of OldCh in Picture with NewCh} + var + I : Integer; + UpCh : Char; + P : Cardinal; + begin + UpCh := StBase.Upcase(OldCh); + if (StrChPosL(Picture,OldCh,P)) or (StrChPosL(Picture,UpCh,P)) then + for I := 1 to Length(Picture) do + if StBase.Upcase(Picture[I]) = UpCh then + Picture[I] := NewCh; + Result := Picture; + end; + + function PackResult(const Picture, S : string) : string; {!!.02} + {-Remove unnecessary blanks from S} + var + step : Integer; + begin + Result := ''; + + for step := 1 to Length(Picture) do + begin + case Picture[step] of + MonthOnlyU, DayOnlyU, NameOnly, NameOnlyU, WeekDayOnly, + WeekDayOnlyU, HourOnlyU, SecOnlyU : + if S[step] <> ' ' then + AppendChar(Result,S[Step]); + TimeOnly : + if S[step] <> ' ' then + AppendChar(Result,S[step]); + else + AppendChar(Result,S[step]); + end; + end; + end; + + procedure MergeIntoPicture(var Picture : string; Ch : Char; I : Integer); + {-Merge I into location in Picture indicated by format character Ch} + var + Tmp : string; + C, + J, K, L : Cardinal; + UCh, + CPJ, + CTI : Char; + OK, Done: Boolean; + step : Cardinal; + begin + {find the start of the subfield} + OK := StrChPosL(Picture,Ch,J); + UCh := StBase.Upcase(Ch); + if (NOT OK) then + begin + if NOT (StrChPosL(Picture, UCh, J)) then + Exit; + end; + + {find the end of the subfield} + K := J; + C := Length(Picture); + while (J <= C) and (StBase.Upcase(Picture[J]) = UCh) do + Inc(J); + Dec(J); + + if (UCh = WeekDayOnlyU) or (UCh = NameOnlyU) then begin + if UCh = WeekDayOnlyU then + case I of + Ord(Sunday)..Ord(Saturday) : + Tmp := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongDayNames[I+1]; + else + Tmp := ''; + end + else + case I of + 1..12 : + Tmp := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongMonthNames[I]; + else + Tmp := ''; + end; + K := Succ(J-K); + if K > Length(Tmp) then + for step := 1 to (K-Length(Tmp)) do + Tmp := Tmp + ' '; + Tmp := Copy(Tmp,1,K); + end else + {convert I to a string} + Str(I:DateLen, Tmp); + + {now merge} + L := Length(Tmp); + Done := False; + CPJ := Picture[J]; + + while (stBase.Upcase(CPJ) = UCh) and not Done do + begin + CTI := Tmp[L]; + if (UCh = NameOnlyU) or (UCh = WeekDayOnlyU) then + begin + case CPJ of + NameOnlyU, WeekDayOnlyU : + CTI := stBase.Upcase(CTI); + end; + end + else{change spaces to 0's if desired} + if (CPJ >= 'a') and (CTI = ' ') then + CTI := '0'; + Picture[J] := CTI; + Done := (J = 1) or (L = 0); + if not Done then + begin + Dec(J); + Dec(L); + end; + CPJ := Picture[J]; + end; + end; + + + procedure MergePictureSt(const Picture : string; var P : string; {!!.02} + MC : Char; const SP : string); {!!.02} + var + I, J : Cardinal; + L : Cardinal; + begin + if NOT (StrChPosL(Picture,MC,I)) then + Exit; + J := 1; + L := Length(SP); + while Picture[I] = MC do begin + {if J <= Length(SP) then} + if (L = 0) or (J > L) then + P[I] := ' ' + else begin + P[I] := SP[J]; + Inc(J); + end; + Inc(I); + end; + end; + + + function DMYtoDateString(const Picture : string; Day, Month, Year, Epoch : Integer; + Pack : Boolean) : string; + {-Merge the month, day, and year into the picture} + var + DOW : Integer; + + begin + Result := Picture; + + Year := ResolveEpoch(Year, Epoch); + + DOW := Integer( DayOfWeekDMY(Day, Month, Year, 0) ); + MergeIntoPicture(Result, MonthOnly, Month); + MergeIntoPicture(Result, DayOnly, Day); + MergeIntoPicture(Result, YearOnly, Year); + MergeIntoPicture(Result, NameOnly, Month); + MergeIntoPicture(Result, WeekDayOnly, DOW); + + {map slashes} + Result := SubstChar(Result, DateSlash, wSlashChar); + + MergePictureSt(Picture, Result, LongDateSub1, wldSub1); + MergePictureSt(Picture, Result, LongDateSub2, wldSub2); + MergePictureSt(Picture, Result, LongDateSub3, wldSub3); + + if Pack then + Result:= PackResult(Picture, Result); + end; + + function StDateToDateString(const Picture : string; const Julian : TStDate; + Pack : Boolean) : string; + {-Convert Julian to a string of the form indicated by Picture} + var + Month, Day, Year : Integer; + begin + Result := Picture; + if (Julian = BadDate) or (Julian > MaxDate) then begin {!!.04} + {map picture characters to spaces} + Result := SubstChar(Result, MonthOnly, ' '); + Result := SubstChar(Result, NameOnly, ' '); + Result := SubstChar(Result, DayOnly, ' '); + Result := SubstChar(Result, YearOnly, ' '); + Result := SubstChar(Result, WeekDayOnly, ' '); + + MergePictureSt(Picture, Result, LongDateSub1, wldSub1); + MergePictureSt(Picture, Result, LongDateSub2, wldSub2); + MergePictureSt(Picture, Result, LongDateSub3, wldSub3); + + {map slashes} + Result := SubstChar(Result, DateSlash, wSlashChar); + end + else begin + {convert Julian to day/month/year} + StDateToDMY(Julian, Day, Month, Year); + + {merge the month, day, and year into the picture} + Result := DMYtoDateString(Picture, Day, Month, Year, 0, Pack); + end; + end; + + function CurrentDateString(const Picture : string; Pack : Boolean) : string; + {-Returns today's date as a string of the specified form} + begin + Result := StDateToDateString(Picture, CurrentDate, Pack); + end; + + function TimeStringToHMS(const Picture, St : string; var H, M, S : Integer) : Boolean; + {-Extract Hours, Minutes, Seconds from St, returning true if string is valid} + var + I, + J : Cardinal; + Tmp, + t1159, + t2359 : string; + begin + {extract hours, minutes, seconds from St} + ExtractFromPicture(Picture, St, HourOnly, H, -1, 0); + ExtractFromPicture(Picture, St, MinOnly, M, -1, 0); + ExtractFromPicture(Picture, St, SecOnly, S, -1, 0); + if (H = -1) or (M = -1) or (S = -1) then begin + Result := False; + Exit; + end; + + {check for TimeOnly} + if (StrChPosL(Picture, TimeOnly, I)) and + (Length(w1159) > 0) and (Length(w2359) > 0) then begin + + Tmp := ''; + J := 1; + while (I <= Cardinal(Length(Picture))) and (Picture[I] = TimeOnly) do begin{!!.02} + // while (Picture[I] = TimeOnly) do begin + //SZ Inc(Tmp[0]); + //SZ Tmp[J] := St[I]; + Tmp := Tmp + St[I]; + Inc(J); + Inc(I); + end; + Tmp := TrimRight(Tmp); + + t1159 := w1159; + t2359 := w2359; + if (Length(Tmp) = 0) then + H := -1 + else if (UpperCase(Tmp) = UpperCase(t2359)) then begin + if (H < 12) then + Inc(H,12) + else if (H=0) or (H > 12) then + {force BadTime} + H := -1; + end + else if (UpperCase(Tmp) = UpperCase(t1159)) then begin + if H = 12 then + H := 0 + else if (H = 0) or (H > 12) then + {force BadTime} + H := -1; + end + else + {force BadTime} + H := -1; + end; + Result := ValidTime(H, M, S); + end; + + function TimeStringToStTime(const Picture, S : string) : TStTime; + {-Convert S, a string of the form indicated by Picture, to a Time variable} + var + Hours, Minutes, Seconds : Integer; + begin + if TimeStringToHMS(Picture, S, Hours, Minutes, Seconds) then + Result := HMStoStTime(Hours, Minutes, Seconds) + else + Result := BadTime; + end; + + function TimeToTimeStringPrim(const Picture : string; T : TStTime; {!!.02} + Pack : Boolean; + const t1159, t2359 : string) : string; {!!.02} + {-Convert T to a string of the form indicated by Picture} + var + Hours, + Minutes, + Seconds : Byte; + L, I, + TPos : Cardinal; + P : string; + OK : Boolean; + C : string;//[1]; + begin + {merge the hours, minutes, and seconds into the picture} + StTimeToHMS(T, Hours, Minutes, Seconds); + Result := Picture; + + {check for TimeOnly} + OK := StrChPosL(Result, TimeOnly, TPos); + if OK then begin + if (Hours >= 12) then + P := t2359 + else + P := t1159; + if (Length(t1159) > 0) and (Length(t2359) > 0) then + case Hours of + 0 : Hours := 12; + 13..23 : Dec(Hours, 12); + end; + end; + + if T = BadTime then begin + {map picture characters to spaces} + Result := SubstChar(Result, HourOnly, ' '); + Result := SubstChar(Result, MinOnly, ' '); + Result := SubstChar(Result, SecOnly, ' '); + end + else begin + {merge the numbers into the picture} + MergeIntoPicture(Result, HourOnly, Hours); + MergeIntoPicture(Result, MinOnly, Minutes); + MergeIntoPicture(Result, SecOnly, Seconds); + end; + + {map colons} + Result := SubstChar(Result, TimeColon, wColonChar); + + {plug in AM/PM string if appropriate} + if OK then begin + if (Length(t1159) = 0) and (Length(t2359) = 0) then begin + C := SubstCharSim(Result[TPos], TimeOnly, ' '); + Result[TPos] := C[1]; + end else if (T = BadTime) and (Length(t1159) = 0) then begin + C := SubstCharSim(Result[TPos], TimeOnly, ' '); + Result[TPos] := C[1]; + end else begin + I := 1; + L := Length(P); + // while (I <= L) and (Result[TPos] = TimeOnly) do begin {!!.01} {!!.03} + while (I <= L) and {!!.03} + (TPos <= Length(Result)) and (Result[TPos] = TimeOnly) do {!!.03} + begin {!!.03} + Result[TPos] := P[I]; + Inc(I); + Inc(TPos); + end; + end; + end; + + if Pack and (T <> BadTime) then + Result := PackResult(Picture, Result); + end; + + function StTimeToTimeString(const Picture : string; const T : TStTime; + Pack : Boolean) : string; + {-Convert T to a string of the form indicated by Picture} + begin + Result := TimeToTimeStringPrim(Picture, T, Pack, w1159, w2359); + end; + + function StTimeToAmPmString(const Picture : string; const T : TStTime; + Pack : Boolean) : string; + {-Convert T to a string of the form indicated by Picture. Times are always + displayed in am/pm format.} + const + t1159 = 'AM'; + t2359 = 'PM'; + var + P : Cardinal; + begin + Result := Picture; + if NOT (StrChPosL(Result, TimeOnly, P)) then + Result := Result + TimeOnly; + Result := TimeToTimeStringPrim(Result, T, Pack, t1159, t2359); + end; + + function CurrentTime : TStTime; + {-Returns current time in seconds since midnight} + begin + Result := Trunc(SysUtils.Time * SecondsInDay); + end; + + function CurrentTimeString(const Picture : string; Pack : Boolean) : string; + {-Returns current time as a string of the specified form} + begin + Result := StTimeToTimeString(Picture, CurrentTime, Pack); + end; + + function MaskCharCount(const P : string; MC : Char) : Integer; {!!.02} + var + I, R, + Len : Cardinal; + OK : Boolean; + begin + OK := StrChPosL(P, MC, I); + R := Ord(OK); + Len := Length(P); + if OK then + while (I+R <= Len) and (P[I+R] = MC) do {!!.01} + Inc(R); + Result := R; + end; + + function InternationalDate(ForceCentury : Boolean) : string; + {-Return a picture mask for a date string, based on Windows' int'l info} + + procedure FixMask(MC : Char; DL : Integer); + var + I, J, AL, D : Cardinal; + MCT : Char; + OK : Boolean; + begin + {find number of matching characters} + OK := StrChPosL(Result, MC, I); + MCT := MC; + if not OK then begin + MCT := StBase.UpCase(MC); + OK := StrChPosL(Result, MCT, I); + end; + if NOT OK then + Exit; + + D := DL; + {pad substring to desired length} + AL := MaskCharCount(Result, MCT); + if AL < D then + for J := 1 to D-AL do + Result := StrChInsertL(Result, MCT, I); + + if MC <> YearOnly then begin + {choose blank/zero padding} + case AL of + 1 : if MCT = MC then + Result := SubstCharSim(Result, MCT, StBase.UpCase(MCT)); + 2 : if MCT <> MC then + Result := SubstCharSim(Result, MCT, MC); + end; + end; + end; + + begin + {copy Windows mask into our var} + Result := wShortDate; + + {if single Day marker, make double} + FixMask(DayOnly, 2); + + {if single Month marker, make double} + FixMask(MonthOnly, 2); + + {force yyyy if desired} + FixMask(YearOnly, 2 shl Ord(ForceCentury)); + end; + + function InternationalLongDate(ShortNames : Boolean; + ExcludeDOW : Boolean) : string; + {-Return a picture mask for a date string, based on Windows' int'l info} + var + I, WC : Cardinal; + OK, + Stop : Boolean; + Temp : string[81]; + + function LongestMonthName : Integer; + var + L, I : Integer; + begin + L := 0; + for I := 1 to 12 do + L := Maxword(L, Length({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongMonthNames[I])); + LongestMonthName := L; + end; + + function LongestDayName : Integer; + var + D : TStDayType; + L : Integer; + begin + L := 0; + for D := Sunday to Saturday do + L := Maxword(L, Length({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongDayNames[Ord(D)+1])); + LongestDayName := L; + end; + + procedure FixMask(MC : Char; DL : Integer); + var + I, J, AL, D : Cardinal; + MCT : Char; + begin + {find first matching mask character} + OK := StrChPosS(Temp, MC, I); + MCT := MC; + if NOT OK then begin + MCT := StBase.UpCase(MC); + OK := StrChPosS(Temp, MCT, I); + end; + if NOT OK then + Exit; + + D := DL; + {pad substring to desired length} + AL := MaskCharCount(Temp, MCT); + if AL < D then begin + for J := 1 to D-AL do + Temp := StrChInsertL(Temp, MCT, I); + end else if (AL > D) then + Temp := StrStDeleteL(Temp, I, AL-D); + + if MC <> YearOnly then + {choose blank/zero padding} + case AL of + 1 : if MCT = MC then + Temp := SubstCharSim(Temp, MCT, StBase.UpCase(MCT)); + 2 : if MCT <> MC then + Temp := SubstCharSim(Temp, MCT, MC); + end; + end; + + begin + {copy Windows mask into temporary var} + Temp := wLongDate; + + if ExcludeDOW then begin + {remove day-of-week and any junk that follows} + if (StrChPosS(Temp, WeekDayOnly,I)) then begin + Stop := False; + WC := I+1; + while (WC <= Length(Temp)) AND (NOT Stop) do + begin + if LoCase(Temp[WC]) in [MonthOnly,DayOnly,YearOnly,NameOnly] then + Stop := TRUE + else + Inc(WC); + end; + if (NOT ShortNames) then + Dec(WC); + Temp := StrStDeleteS(Temp, I, WC); + end; + end + else if ShortNames then + FixMask(WeekDayOnly, 3) + else if MaskCharCount(Temp, WeekdayOnly) = 4 then + FixMask(WeekDayOnly, LongestDayName); + + {fix month names} + if ShortNames then + FixMask(NameOnly, 3) + else if MaskCharCount(Temp, NameOnly) = 4 then + FixMask(NameOnly, LongestMonthName); + + {if single Day marker, make double} + FixMask(DayOnly, 2); + + {if single Month marker, make double} + FixMask(MonthOnly, 2); + + {force yyyy} + FixMask(YearOnly, 4); + + Result := Temp; + end; + + function InternationalTime(ShowSeconds : Boolean) : string; + {-Return a picture mask for a time string, based on Windows' int'l info} + var + ML, + I : Integer; + begin + {format the default string} + + SetLength(Result,21); + Result := 'hh:mm:ss'; + if not wTLZero then + Result[1] := HourOnlyU; + + {show seconds?} + if not ShowSeconds then + SetLength(Result,5); + + {handle international AM/PM markers} + if w12Hour then begin + ML := Maxword(Length(w1159), Length(w2359)); + if (ML <> 0) then begin + AppendChar(Result,' '); + for I := 1 to ML do + AppendChar(Result, TimeOnly); + end; + end; + end; + + procedure SetDefaultYear; + {-Initialize DefaultYear and DefaultMonth} + var + Month, Day : Word; + T : TDateTime; + W : Word; + begin + T := Now; + W := DefaultYear; + DecodeDate(T,W,Month,Day); + DefaultYear := W; + DefaultMonth := Month; + end; + + procedure ResetInternationalInfo; + var + I : Integer; + S : array[0..20] of char; + + procedure ExtractSubString(SubChar : Char; Dest : string); + var + I, L, P : Cardinal; + begin +// SetLength(Dest,sizeof(wldSub1)); +// FillChar(Dest[1], SizeOf(wldSub1), 0); + Dest := StringOfChar(#0, Succ(High(wldSub1))); //SZ: not length! [*] + if NOT (StrChPosS(wLongDate, '''',I)) then + Exit; + + {delete the first quote} + wLongDate := StrChDeleteS(wLongDate, I); + + {assure that there is another quote} + if NOT (StrChPosS(wLongDate, '''',P)) then + Exit; + + {copy substring into Dest, replace substring with SubChar} + L := 1; + while wLongDate[I] <> '''' do + if L < SizeOf(wldSub1) then begin + Dest[L] := wLongDate[I]; + Inc(L); + wLongDate[I] := SubChar; + Inc(I); + end else + wLongDate := StrChDeleteL(wLongDate, I); + + {delete the second quote} + wLongDate := StrChDeleteL(wLongDate, I); + end; + + begin + wTLZero := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongTimeFormat[2] = 'h'; + w12Hour := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongTimeFormat[length({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongTimeFormat)] = 'M'; + + wColonChar := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}TimeSeparator; + wSlashChar := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DateSeparator; + + {$IFDEF FPC} + w1159 := ''; // ???????????? + w2359 := ''; + {$ELSE} + GetProfileString('intl','s1159','AM', S, Length(S)); + w1159 := StrPas(S); + GetProfileString('intl','s2359','PM', S, Length(S)); + w2359 := StrPas(S); + {$ENDIF} + + {get short date mask and fix it up} + wShortDate := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}ShortDateFormat; + for I := 1 to Length(wShortDate) do + if (wShortDate[I] = wSlashChar) then + wShortDate[I] := '/'; + + {get long date mask and fix it up} + wLongDate := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}LongDateFormat; + ExtractSubString(LongDateSub1, wldSub1); + ExtractSubString(LongDateSub2, wldSub2); + ExtractSubString(LongDateSub3, wldSub3); + + {replace ddd/dddd with www/wwww} + I := pos('ddd',wLongDate); + if I > 0 then begin + while wLongDate[I] = 'd' do begin + wLongDate[I] := 'w'; + Inc(I); + end; + end; + + {replace MMM/MMMM with nnn/nnnn} + if pos('MMM',wLongDate) > 0 then + while (pos('M',wLongDate) > 0) do + wLongDate[pos('M',wLongDate)] := 'n'; + + {deal with oddities concerning . and ,} + for I := 1 to Length(wLongDate)-1 do begin + case wLongDate[I] of + '.', ',' : + if wLongDate[I+1] <> ' ' then + wLongDate := StrChInsertS(wLongDate, ' ', I+1); + end; + end; + end; + + +initialization + {initialize DefaultYear and DefaultMonth} + SetDefaultYear; + ResetInternationalInfo; +end. diff --git a/components/systools/source/run/stdecmth.pas b/components/systools/source/run/stdecmth.pas new file mode 100644 index 000000000..0a8f23a3a --- /dev/null +++ b/components/systools/source/run/stdecmth.pas @@ -0,0 +1,1308 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDecMth.pas 4.04 *} +{*********************************************************} +{* SysTools: Class for doing decimal arithmetic *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit StDecMth; + +interface + +{Note: StDecMth declares and implements TStDecimal. This is a fixed- + point value with a total of 38 significant digits of which + 16 are to the right of the decimal point.} + +uses + SysUtils; + +type + TStRoundMethod = ( {different rounding methods...} + rmNormal, {..normal (round away from zero if half way)} + rmTrunc, {..truncate (always round to zero)} + rmBankers, {..bankers (round to even digit if half way)} + rmUp); {..force round up (always round from zero)} + + TStInt128 = array [0..3] of longint; // must be longint, not DWORD + + TStDecimal = class + private + FInt : TStInt128; + protected + function dcGetAsStr : AnsiString; + procedure dcSetFromStr(const aValue : AnsiString); {!!.02} + public + constructor Create; + destructor Destroy; override; + + function Compare(X : TStDecimal) : integer; + {-returns <0 if Self < X, 0 is equal, >0 otherwise} + function IsNegative : boolean; + {-returns Self < 0.0} + function IsOne : boolean; + {-returns Self = 1.0} + function IsPositive : boolean; + {-returns Self > 0.0} + function IsZero : boolean; + {-returns Self = 0.0} + procedure SetToOne; + {-sets Self equal to 1.0} + procedure SetToZero; + {-sets Self equal to 0.0} + + procedure Assign(X : TStDecimal); + {-sets Self equal to X} + procedure AssignFromFloat(aValue : double); + {-sets Self equal to aValue} + procedure AssignFromInt(aValue : integer); + {-sets Self equal to aValue} + + function AsFloat : double; + {-returns Self as an floating point value} + function AsInt(aRound : TStRoundMethod) : integer; + {-returns Self as an integer, rounded} + + procedure Abs; + {-calculates Self := Abs(Self)} + procedure Add(X : TStDecimal); + {-calculates Self := Self + X} + procedure AddOne; + {-calculates Self := Self + 1.0} + procedure ChangeSign; + {-calculates Self := ChgSign(Self)} + procedure Divide(X : TStDecimal); + {-calculates Self := Self div X} + procedure Multiply(X : TStDecimal); + {-calculates Self := Self * X} + procedure RaiseToPower(N : integer); + {-calculates Self := Self ^ N} + procedure Round(aRound : TStRoundMethod; aDecPl : integer); + {-calculates Self := Round(Self)} + procedure Subtract(X : TStDecimal); + {-calculates Self := Self - X} + procedure SubtractOne; + {-calculates Self := Self - 1} + + property AsString : AnsiString read dcGetAsStr write dcSetFromStr; + {-returns Self as a string, sets Self from a string} + end; + +implementation + +uses + StConst, + StBase; + +type + TStInt256 = array [0..7] of integer; + TStInt192 = array [0..5] of integer; + +const + MaxDecPl = 16; + + Int128One_0 = longint($6FC10000); + Int128One_1 = longint($002386F2); + + PowerOf10 : array [0..MaxDecPl div 2] of integer = + (1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + 100000000); + +{===Helper routines==================================================} +procedure Int256Div10E8(var X : TStInt256; var aRem : integer); +{Note: this routine assumes X is positive} +asm + push ebx // save ebx + + push edx // save address of remainder variable + + mov ecx, 100000000 // we're dividing by 10^8 + mov ebx, eax // ebx points to X + + xor edx, edx // start off with high dividend digit zero + mov eax, [ebx+28] // get last 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx+28], eax // save highest quotient digit + + mov eax, [ebx+24] // get next 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx+24], eax // save next quotient digit + + mov eax, [ebx+20] // get next 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx+20], eax // save next quotient digit + + mov eax, [ebx+16] // get next 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx+16], eax // save next quotient digit + + mov eax, [ebx+12] // get next 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx+12], eax // save next quotient digit + + mov eax, [ebx+8] // get next 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx+8], eax // save next quotient digit + + mov eax, [ebx+4] // get next 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx+4], eax // save next quotient digit + + mov eax, [ebx] // get first 32-bit digit + div ecx // divide by 10: eax is quotient, edx remainder + mov [ebx], eax // save first quotient digit + + pop eax // pop off the address of remainder variable + mov [eax], edx // store remainder + + pop ebx // restore ebx +end; +{--------} +procedure Int192Times10E8(var X : TStInt192); +{Note: this routine assumes X is positive} +asm + push ebx // save ebx + push ebp // save ebp + + mov ecx, 100000000 // we're multiplying by 10^8 + mov ebx, eax // ebx points to X + + mov eax, [ebx] // get the first 32-bit digit + mul ecx // multiply it by 10^8 to give answer in edx:eax + mov [ebx], eax // save first digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+4] // get the second 32-bit digit + mul ecx // multiply it by 10^8 to give answer in edx:eax + add eax, ebp // add the overflow from the first digit + adc edx, 0 + mov [ebx+4], eax // save second digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+8] // get the third 32-bit digit + mul ecx // multiply it by 10^8 to give answer in edx:eax + add eax, ebp // add the overflow from the second digit + adc edx, 0 + mov [ebx+8], eax // save third digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+12] // get the fourth 32-bit digit + mul ecx // multiply it by 10^8 to give answer in edx:eax + add eax, ebp // add the overflow from the third digit + adc edx, 0 + mov [ebx+12], eax // save fourth digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+16] // get the fifth 32-bit digit + mul ecx // multiply it by 10^8 to give answer in edx:eax + add eax, ebp // add the overflow from the fourth digit + adc edx, 0 + mov [ebx+16], eax // save fifth digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+20] // get the sixth 32-bit digit + mul ecx // multiply it by 10^8 to give answer in edx:eax + add eax, ebp // add the overflow from the fifth digit + mov [ebx+20], eax // save sixth digit of result + + pop ebp // restore ebp + pop ebx // restore ebx +end; +{--------} +function Int32MultPrim(X, Y : longint; + var P : longint; Carry : longint) : longint; +asm + {Note: calculates X * Y + P + Carry + returns answer in P, with overflow as result value} + mul edx + add eax, [ecx] + adc edx, 0 + add eax, Carry + adc edx, 0 + mov [ecx], eax + mov eax, edx +end; +{--------} +procedure Int128Add(var X : TStInt128; const Y : TStInt128); +asm + push ebx + mov ecx, [edx] + mov ebx, [edx+4] + add [eax], ecx + adc [eax+4], ebx + mov ecx, [edx+8] + mov ebx, [edx+12] + adc [eax+8], ecx + adc [eax+12], ebx + pop ebx +end; +{--------} +procedure Int128AddInt(var X : TStInt128; aDigit : integer); +asm + add [eax], edx + adc dword ptr [eax+4], 0 + adc dword ptr [eax+8], 0 + adc dword ptr [eax+12], 0 +end; +{--------} +procedure Int128ChgSign(var X : TStInt128); +asm + mov ecx, [eax] + mov edx, [eax+4] + not ecx + not edx + add ecx, 1 + adc edx, 0 + mov [eax], ecx + mov [eax+4], edx + mov ecx, [eax+8] + mov edx, [eax+12] + not ecx + not edx + adc ecx, 0 + adc edx, 0 + mov [eax+8], ecx + mov [eax+12], edx +end; +{--------} +function Int128Compare(const X, Y : TStInt128) : integer; +asm + // Can be called from pascal + // All registers are preserved, except eax, which returns the + // result of the comparison + push ebx + push ecx + mov ecx, [eax+12] + mov ebx, [edx+12] + xor ecx, $80000000 + xor ebx, $80000000 + cmp ecx, ebx + jb @@LessThan + ja @@GreaterThan + mov ecx, [eax+8] + mov ebx, [edx+8] + cmp ecx, ebx + jb @@LessThan + ja @@GreaterThan + mov ecx, [eax+4] + mov ebx, [edx+4] + cmp ecx, ebx + jb @@LessThan + ja @@GreaterThan + mov ecx, [eax] + mov ebx, [edx] + cmp ecx, ebx + jb @@LessThan + ja @@GreaterThan + xor eax, eax + jmp @@Exit +@@LessThan: + mov eax, -1 + jmp @@Exit +@@GreaterThan: + mov eax, 1 +@@Exit: + pop ecx + pop ebx +end; +{--------} +procedure Int192SHL(var X : TStInt192); +asm + // DO NOT CALL FROM PASCAL + // IN: eax -> 192-bit integer to shift left + // OUT: eax -> 192-bit integer shifted left + // CF = most significant bit shifted out + // All registers are preserved + push ebx + push ecx + mov ebx, [eax] + mov ecx, [eax+4] + shl ebx, 1 + rcl ecx, 1 + mov [eax], ebx + mov [eax+4], ecx + mov ebx, [eax+8] + mov ecx, [eax+12] + rcl ebx, 1 + rcl ecx, 1 + mov [eax+8], ebx + mov [eax+12], ecx + mov ebx, [eax+16] + mov ecx, [eax+20] + rcl ebx, 1 + rcl ecx, 1 + mov [eax+16], ebx + mov [eax+20], ecx + pop ecx + pop ebx +end; +{--------} +procedure Int128RCL(var X : TStInt128); +asm + // DO NOT CALL FROM PASCAL + // IN: eax -> 128-bit integer to shift left + // CF = least significant bit to shift in + // OUT: eax -> 128-bit integer shifted left + // CF -> topmost bit shifted out + // All registers are preserved + push ebx + push ecx + mov ebx, [eax] + mov ecx, [eax+4] + rcl ebx, 1 + rcl ecx, 1 + mov [eax], ebx + mov [eax+4], ecx + mov ebx, [eax+8] + mov ecx, [eax+12] + rcl ebx, 1 + rcl ecx, 1 + mov [eax+8], ebx + mov [eax+12], ecx + pop ecx + pop ebx +end; +{--------} +procedure Int128FastDivide(var X : TStInt192; + var Y, aRem : TStInt128); +asm + push ebp + push ebx + push edi + push esi + + mov esi, eax // esi -> dividend + mov edi, edx // edi -> divisor + mov ebp, ecx // ebp -> remainder + + mov ecx, 192 // we'll do the loop for all 192 bits in the + // dividend + + xor eax, eax // zero the remainder + mov [ebp], eax + mov [ebp+4], eax + mov [ebp+8], eax + mov [ebp+12], eax + +@@GetNextBit: + mov eax, esi // shift the dividend left, and... + call Int192SHL + mov eax, ebp // ...shift the topmost bit into the remainder + call Int128RCL + + mov eax, ebp // compare the remainder with the divisor + mov edx, edi + call Int128Compare + + cmp eax, 0 // if the remainder is smaller, we can't + jl @@TooSmall // subtract the divisor + + // essentially we've shown that the divisor + // divides the remainder exactly once, so + + add dword ptr [esi], 1 // add one to the quotient + + mov eax, [ebp] // subtract the divisor from the remainder + mov ebx, [ebp+4] + sub eax, [edi] + sbb ebx, [edi+4] + mov [ebp], eax + mov [ebp+4], ebx + mov eax, [ebp+8] + mov ebx, [ebp+12] + sbb eax, [edi+8] + sbb ebx, [edi+12] + mov [ebp+8], eax + mov [ebp+12], ebx + +@@TooSmall: + dec ecx // go get the next bit to work on + jnz @@GetNextBit + + pop esi + pop edi + pop ebx + pop ebp +end; +{--------} +function Int128DivInt(var X : TStInt128; aDivisor : integer) : integer; +{Note: this routine assumes X is positive} +asm + push ebx // save ebx + + mov ecx, edx // ecx is now the divisor + mov ebx, eax // ebx points to X + + xor edx, edx // start off with high dividend digit zero + mov eax, [ebx+12] // get last 32-bit digit + div ecx // divide by ecx: eax is quotient, edx remainder + mov [ebx+12], eax // save highest quotient digit + + mov eax, [ebx+8] // get next 32-bit digit + div ecx // divide by ecx: eax is quotient, edx remainder + mov [ebx+8], eax // save next quotient digit + + mov eax, [ebx+4] // get next 32-bit digit + div ecx // divide by ecx: eax is quotient, edx remainder + mov [ebx+4], eax // save next quotient digit + + mov eax, [ebx] // get first 32-bit digit + div ecx // divide by ecx: eax is quotient, edx remainder + mov [ebx], eax // save first quotient digit + + mov eax, edx // return remainder + + pop ebx // restore ebx +end; +{--------} +procedure Int128Divide(var X, Y : TStInt128); +var + XTemp : TStInt192; + Rem : TStInt128; +begin + {note: the easy cases have been dealt with + X and Y are both positive + X will be set to the quotient X/Y and Y will be trashed} + + {we need to increase the number of decimal places to 32, so convert + the 128 bit dividend to a 192 bit one and multiply by 10^16} + XTemp[0] := X[0]; + XTemp[1] := X[1]; + XTemp[2] := X[2]; + XTemp[3] := X[3]; + XTemp[4] := 0; + XTemp[5] := 0; + Int192Times10E8(XTemp); + Int192Times10E8(XTemp); + + {Note: this algorithm follows that described by Knuth in volume 2 of + The Art of Computer Programming. Algorithm D of section 4.3 + as applied to binary numbers (radix=2)} + + {divide the 192-bit dividend by the 128-bit divisor} + Int128FastDivide(XTemp, Y, Rem); + + {have we overflowed? ie, have we divided a very big number by one + much less than zero} + if (XTemp[3] < 0) or (XTemp[4] <> 0) or (XTemp[5] <> 0) then + raise EStDecMathError.Create(stscDecMathDivOverflowS); + + {return the result of the computation} + X[0] := XTemp[0]; + X[1] := XTemp[1]; + X[2] := XTemp[2]; + X[3] := XTemp[3]; +end; +{--------} +procedure Int128Multiply(var X, Y : TStInt128); +var + P : TStInt256; + XIsNeg : boolean; + YIsNeg : boolean; + YInx : integer; + YDigit : integer; + Carry : integer; + YTemp : TStInt128; +begin + {Note: calculates X * Y and puts the answer in X} + + {get rid of the easy cases where one of the operands is zero} + if (X[0] = 0) and (X[1] = 0) and (X[2] = 0) and (X[3] = 0) then + Exit; + if (Y[0] = 0) and (Y[1] = 0) and (Y[2] = 0) and (Y[3] = 0) then begin + X[0] := 0; + X[1] := 0; + X[2] := 0; + X[3] := 0; + Exit; + end; + + {we might need to trash Y, so we use a local variable} + YTemp[0] := Y[0]; + YTemp[1] := Y[1]; + YTemp[2] := Y[2]; + YTemp[3] := Y[3]; + + {convert both operands to positive values: we'll fix the sign later} + XIsNeg := X[3] < 0; + if XIsNeg then + Int128ChgSign(X); + YIsNeg := YTemp[3] < 0; + if YIsNeg then + Int128ChgSign(YTemp); + + {initialize the temporary product} + P[0] := 0; + P[1] := 0; + P[2] := 0; + P[3] := 0; + P[4] := 0; + P[5] := 0; + P[6] := 0; + P[7] := 0; + + {for every digit in Y we shall multiply by all the X digits and sum} + for YInx := 0 to 3 do begin + + {get the Y digit} + YDigit := YTemp[YInx]; + + {there's only something to do if the Y digit is non-zero} + if (YDigit <> 0) then begin + + {multiply this digit with all the X digits, storing the result + in the temporary product} + Carry := Int32MultPrim(X[0], YDigit, P[YInx], 0); + Carry := Int32MultPrim(X[1], YDigit, P[YInx + 1], Carry); + Carry := Int32MultPrim(X[2], YDigit, P[YInx + 2], Carry); + P[YInx + 4] := Int32MultPrim(X[3], YDigit, P[YInx + 3], Carry); + end; + end; + + {the product has 32 decimal places, so divide by 10^8 twice to get + the answer to the 16 decimal places we need} + Int256Div10E8(P, Carry); + Int256Div10E8(P, Carry); + + {note: if Carry <> 0 then we're losing precision} + + {check for multiplication overflow} + if (P[3] < 0) or + (P[4] <> 0) or (P[5] <> 0) or (P[6] <> 0) or (P[7] <> 0) then + raise EStDecMathError.Create(stscDecMathMultOverflowS); + + {return the value in X, remembering to set the sign} + X[0] := P[0]; + X[1] := P[1]; + X[2] := P[2]; + X[3] := P[3]; + + (* + {round if necessary} + if (Carry >= 500000000) then + Int128AddInt(X, 1); + *) + + {set the sign} + if (XIsNeg xor YIsNeg) then + Int128ChgSign(X); +end; +{--------} +procedure Int128TimesInt(var X : TStInt128; aValue : integer); +{Note: this routine assumes X is positive} +asm + push ebx // save ebx + push ebp // save ebp + + mov ecx, edx // we're multiplying by aValue + mov ebx, eax // ebx points to X + + mov eax, [ebx] // get the first 32-bit digit + mul ecx // multiply it by 10 to give answer in edx:eax + mov [ebx], eax // save first digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+4] // get the second 32-bit digit + mul ecx // multiply it by 10 to give answer in edx:eax + add eax, ebp // add the overflow from the first digit + adc edx, 0 + mov [ebx+4], eax // save second digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+8] // get the third 32-bit digit + mul ecx // multiply it by 10 to give answer in edx:eax + add eax, ebp // add the overflow from the second digit + adc edx, 0 + mov [ebx+8], eax // save second digit of result + mov ebp, edx // save overflow + + mov eax, [ebx+12] // get the third 32-bit digit + mul ecx // multiply it by 10 to give answer in edx:eax + add eax, ebp // add the overflow from the second digit + mov [ebx+12], eax // save third digit of result + + pop ebp // restore ebp + pop ebx // restore ebx +end; +{--------} +procedure Int128Round(var X : TStInt128; + aRound : TStRoundMethod; + aDecPl : integer); +var + Rem : integer; + HadRem : boolean; + AddOne : boolean; + Expnt : integer; + NeedInt : boolean; +begin + {Assumptions: X is positive, 0 <= aDecPl <= MaxDecPl + --the caller *must* ensure these} + + {if the number of decimal places is -1, it's a special signal to + perform the rounding to an integer, but not to multiply the result + by 10^16 at the end; the caller is AsInt, in other words} + if (aDecPl >= 0) then + NeedInt := false + else begin + NeedInt := true; + aDecPl := 0; + end; + + {if we're asked to round to the precision of the type, there's + nothing to do} + if (aDecPl = MaxDecPl) then + Exit; + + {perform the required rounding} + AddOne := false; // keep the compiler happy + case aRound of + rmNormal : + begin + {to do normal rounding: divide by the required power of ten, + if the most significant digit of the remainder was 5 or more, + we'll add one to the result} + Expnt := MaxDecPl - aDecPl - 1; + if (Expnt > 0) then begin + if (Expnt > 8) then begin + Int128DivInt(X, PowerOf10[8]); + dec(Expnt, 8); + end; + Int128DivInt(X, PowerOf10[Expnt]); + end; + AddOne := Int128DivInt(X, 10) >= 5; + end; + rmTrunc : + begin + {to truncate: just divide by the required power of ten} + Expnt := MaxDecPl - aDecPl; + if (Expnt > 8) then begin + Int128DivInt(X, PowerOf10[8]); + dec(Expnt, 8); + end; + Int128DivInt(X, PowerOf10[Expnt]); + AddOne := false; + end; + rmBankers : + begin + {to do bankers rounding: + - divide by the required power of ten, checking to see if + there's a non-zero remainder + - if the most significant digit of the remainder was greater + than 5, we'll add one to the result + - if the most significant digit of the remainder was 5 and + there was at least one other digit in the remainder, we'll + add one to the result + - if the most significant digit of the remainder was 5 and + there were no other digits in the remainder, determine if + the result is odd; if it is, we'll add one to the result} + HadRem := false; + if ((MaxDecPl - aDecPl) > 1) then begin + Expnt := MaxDecPl - aDecPl - 1; + if (Expnt > 8) then begin + if (Int128DivInt(X, PowerOf10[8]) <> 0) then + HadRem := true; + dec(Expnt, 8); + end; + if (Int128DivInt(X, PowerOf10[Expnt]) <> 0) then + HadRem := true; + end; + Rem := Int128DivInt(X, 10); + AddOne := (Rem > 5) or + ((Rem = 5) and HadRem) or + ((Rem = 5) and Odd(X[0])); + end; + rmUp : + begin + {to always round up: divide by the required power of ten, + if there was a remainder, we'll add one to the result} + AddOne := false; + Expnt := MaxDecPl - aDecPl; + if (Expnt > 8) then begin + if (Int128DivInt(X, PowerOf10[8]) <> 0) then + AddOne := true; + dec(Expnt, 8); + end; + if (Int128DivInt(X, PowerOf10[Expnt]) <> 0) then + AddOne := true; + end; + end;{case} + + {add one to the result, if required} + if AddOne then + Int128AddInt(X, 1); + + {finally, multiply by the required power of ten} + if not NeedInt then begin + Expnt := MaxDecPl - aDecPl; + if (Expnt > 8) then begin + Int128TimesInt(X, PowerOf10[8]); + dec(Expnt, 8); + end; + Int128TimesInt(X, PowerOf10[Expnt]); + end; +end; +{====================================================================} + + +{====================================================================} +constructor TStDecimal.Create; +begin + {create the ancestor} + inherited Create; + {note: the internal number will be automatically zero} +end; +{--------} +destructor TStDecimal.Destroy; +begin + {free the ancestor} + inherited Destroy; +end; +{--------} +procedure TStDecimal.Abs; +begin + if (FInt[3] < 0) then + Int128ChgSign(FInt); +end; +{--------} +procedure TStDecimal.Add(X : TStDecimal); +begin + if (X <> nil) then + Int128Add(FInt, X.FInt); +end; +{--------} +procedure TStDecimal.AddOne; +var + One : TStInt128; +begin + One[0] := Int128One_0; + One[1] := Int128One_1; + One[2] := 0; + One[3] := 0; + Int128Add(FInt, One); +end; +{--------} +function TStDecimal.AsFloat : double; +begin + Result := StrToFloat(AsString); +end; +{--------} +function TStDecimal.AsInt(aRound : TStRoundMethod) : integer; +var + X : TStInt128; + IsNeg : boolean; +begin + {get the current value locally} + X[0] := FInt[0]; + X[1] := FInt[1]; + X[2] := FInt[2]; + X[3] := FInt[3]; + + {force it to be positive} + IsNeg := X[3] < 0; + if IsNeg then + Int128ChgSign(X); + + {round it to an integer} + Int128Round(X, aRound, -1); + + {check for errors (the least significant digit cannot be negative, + and all the others must be zero)} + if (X[0] < 0) or (X[1] <> 0) or (X[2] <> 0) or (X[3] <> 0) then + raise EStDecMathError.Create(stscDecMathAsIntOverflowS); + + {return the result} + if IsNeg then + Result := -X[0] + else + Result := X[0]; +end; +{--------} +procedure TStDecimal.Assign(X : TStDecimal); +begin + if (X = nil) then + SetToZero + else begin + FInt[0] := X.FInt[0]; + FInt[1] := X.FInt[1]; + FInt[2] := X.FInt[2]; + FInt[3] := X.FInt[3]; + end; +end; +{--------} +procedure TStDecimal.AssignFromFloat(aValue : double); +begin + AsString := Format('%38.16f', [aValue]); +end; +{--------} +procedure TStDecimal.AssignFromInt(aValue : integer); +begin + FInt[0] := System.Abs(aValue); + FInt[1] := 0; + FInt[2] := 0; + FInt[3] := 0; + Int128TimesInt(FInt, PowerOf10[8]); + Int128TimesInt(FInt, PowerOf10[8]); + if (aValue < 0) then + Int128ChgSign(FInt); +end; +{--------} +procedure TStDecimal.ChangeSign; +begin + Int128ChgSign(FInt); +end; +{--------} +function TStDecimal.Compare(X : TStDecimal) : integer; +begin + Compare := Int128Compare(FInt, X.FInt); +end; +{--------} +function TStDecimal.dcGetAsStr : AnsiString; +var + X : TStInt128; + i : integer; + Rem : integer; + IsNeg : boolean; + ChStack: array [0..47] of AnsiChar; + // this is ample for 38 digits + punctuation + ChSP : integer; +begin + {initialize the stack} + ChSP := 0; + + {since we're going to trash the value, store it locally} + X[0] := FInt[0]; + X[1] := FInt[1]; + X[2] := FInt[2]; + X[3] := FInt[3]; + + {make sure it's positive} + IsNeg := X[3] < 0; + if IsNeg then + Int128ChgSign(X); + + {push the least significant digits (those that will appear after the + radix point)} + for i := 1 to MaxDecPl do begin + Rem := Int128DivInt(X, 10); + ChStack[ChSP] := AnsiChar(Rem + ord('0')); + inc(ChSP); + end; + + {push the radix point} + ChStack[ChSP] := AnsiChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator); + inc(ChSP); + + {repeat until the local value is zero} + repeat + Rem := Int128DivInt(X, 10); + ChStack[ChSP] := AnsiChar(Rem + ord('0')); + inc(ChSP); + until (X[0] = 0) and (X[1] = 0) and (X[2] = 0) and (X[3] = 0); + + {if the value was negative, push a minus sign} + if IsNeg then begin + ChStack[ChSP] := '-'; + inc(ChSP); + end; + + {construct the result value by popping off characters} + SetLength(Result, ChSP); + i := 1; + while (ChSP <> 0) do begin + dec(ChSP); + Result[i] := ChStack[ChSP]; + inc(i); + end; +end; +{--------} +procedure TStDecimal.dcSetFromStr(const aValue : AnsiString); {!!.02} +var + State : (ScanStart, ScanSign, ScanRadix, ScanBefore, + ScanAfter, ScanEnd, GotError); + i : integer; + Ch : AnsiChar; + IsNeg : boolean; + DecPlCount : integer; +begin + {Note: this implements the following DFA: + + ScanStart --space--> ScanStart + ScanStart --plus---> ScanSign + ScanStart --minus--> ScanSign + ScanStart --digit--> ScanBefore + ScanStart --radix--> ScanRadix + + ScanSign --radix--> ScanRadix + ScanSign --digit--> ScanBefore + + ScanRadix --digit--> ScanAfter + + ScanBefore --radix--> ScanAfter + ScanBefore --digit--> ScanBefore + ScanBefore --space--> ScanEnd + + ScanAfter --digit--> ScanAfter + ScanAfter --space--> ScanEnd + + ScanEnd --space--> ScanEnd + + The terminating states are ScanBefore, ScanAfter and ScanEnd; in + other words, a valid numeric string cannot end in a radix point. + } + + {initialize} + SetToZero; + DecPlCount := 0; + IsNeg := false; + State := ScanStart; + + {read through the input string} + for i := 1 to length(aValue) do begin + + {get the current character} + Ch := aValue[i]; + + case State of + ScanStart : + begin + if ('0' <= Ch) and (Ch <= '9') then begin + FInt[0] := ord(Ch) - ord('0'); + State := ScanBefore; + end + else if (Ch = '+') then begin + State := ScanSign; + end + else if (Ch = '-') then begin + IsNeg := true; + State := ScanSign; + end + else if (Ch = AnsiChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator)) then begin + State := ScanRadix; + end + else if (Ch <> ' ') then + State := GotError; + end; + ScanSign : + begin + if ('0' <= Ch) and (Ch <= '9') then begin + FInt[0] := ord(Ch) - ord('0'); + State := ScanBefore; + end + else if (Ch = AnsiChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator)) then begin + State := ScanRadix; + end + else + State := GotError; + end; + ScanRadix : + begin + if ('0' <= Ch) and (Ch <= '9') then begin + inc(DecPlCount); + Int128TimesInt(FInt, 10); + Int128AddInt(FInt, ord(Ch) - ord('0')); + State := ScanAfter; + end + else + State := GotError; + end; + ScanBefore : + begin + if ('0' <= Ch) and (Ch <= '9') then begin + Int128TimesInt(FInt, 10); + Int128AddInt(FInt, ord(Ch) - ord('0')); + end + else if (Ch = AnsiChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator)) then begin + State := ScanAfter; + end + else if (Ch = ' ') then + State := ScanEnd + else + State := GotError; + end; + ScanAfter : + begin + if ('0' <= Ch) and (Ch <= '9') then begin + inc(DecPlCount); + if (DecPlCount <= MaxDecPl) then begin + Int128TimesInt(FInt, 10); + Int128AddInt(FInt, ord(Ch) - ord('0')); + end; + end + else if (Ch = ' ') then + State := ScanEnd + else + State := GotError; + end; + ScanEnd : + begin + if (Ch <> ' ') then + State := GotError; + end; + GotError : + begin + Break; + end; + end; + end; + + if (State <> ScanBefore) and + (State <> ScanAfter) and + (State <> ScanEnd) then + raise EStDecMathError.Create(stscDecMathConversionS); + + {make sure we have the correct number of decimal places} + if (MaxDecPl > DecPlCount) then begin + DecPlCount := MaxDecPl - DecPlCount; + if (DecPlCount > 8) then begin + Int128TimesInt(FInt, Powerof10[8]); + dec(DecPlCount, 8); + end; + Int128TimesInt(FInt, Powerof10[DecPlCount]); + end; + + {force negative, if required} + if IsNeg then + Int128ChgSign(FInt); +end; +{--------} +procedure TStDecimal.Divide(X : TStDecimal); +var + TempX : TStInt128; + IsNeg : boolean; + XIsNeg : boolean; +begin + {easy case: X is nil or zero} + if (X = nil) or X.IsZero then + raise EStDecMathError.Create(stscDecMathDivByZeroS); + + {easy case: Self is zero} + if IsZero then + Exit; + + {we might have to change X, so make it local} + TempX[0] := X.FInt[0]; + TempX[1] := X.FInt[1]; + TempX[2] := X.FInt[2]; + TempX[3] := X.FInt[3]; + + {force the divisor and dividend positive} + IsNeg := FInt[3] < 0; + if IsNeg then + Int128ChgSign(FInt); + XIsNeg := TempX[3] < 0; + if XIsNeg then + Int128ChgSign(TempX); + + {easy case: X is 1.0: set the correct sign} + if (TempX[0] = Int128One_0) and (TempX[1] = Int128One_1) and + (TempX[2] = 0) and (TempX[3] = 0) then begin + if (IsNeg xor XIsNeg) then + Int128ChgSign(FInt); + Exit; + end; + + {easy case: compare the dividend and divisor: if they're equal, + set ourselves to 1.0 with the correct sign} + if (Int128Compare(FInt, TempX) = 0) then begin + FInt[0] := Int128One_0; + FInt[1] := Int128One_1; + FInt[2] := 0; + FInt[3] := 0; + if (IsNeg xor XIsNeg) then + Int128ChgSign(FInt); + Exit; + end; + + {no more easy cases: just do the division} + Int128Divide(FInt, TempX); + + {set the sign} + if (IsNeg xor XIsNeg) then + Int128ChgSign(FInt); +end; +{--------} +function TStDecimal.IsNegative : boolean; +begin + {if the most significant longint is negative, so is the value} + Result := FInt[3] < 0; +end; +{--------} +function TStDecimal.IsOne : boolean; +begin + Result := (FInt[0] = Int128One_0) and (FInt[1] = Int128One_1) and + (FInt[2] = 0) and (FInt[3] = 0); +end; +{--------} +function TStDecimal.IsPositive : boolean; +begin + {if the most significant longint is positive, so is the value; if it + is zero, one of the other longints must be non-zero for the value + to be positive} + Result := (FInt[3] > 0) or + ((FInt[3] = 0) and + ((FInt[2] <> 0) or (FInt[1] <> 0) or (FInt[0] <> 0))); +end; +{--------} +function TStDecimal.IsZero : boolean; +begin + Result := (FInt[0] = 0) and (FInt[1] = 0) and + (FInt[2] = 0) and (FInt[3] = 0); +end; +{--------} +procedure TStDecimal.Multiply(X : TStDecimal); +begin + if (X = nil) then + SetToZero + else + Int128Multiply(FInt, X.FInt); +end; +{--------} +procedure TStDecimal.RaiseToPower(N : integer); +var + Accum : TStInt128; + Mask : longint; + IsNeg : boolean; +begin + {take care of some easy cases} + if (N < 0) then + raise EStDecMathError.Create(stscDecMathNegExpS); + if (N = 0) then begin + SetToOne; + Exit; + end; + if (N = 1) then + Exit; + + {force the value positive} + IsNeg := FInt[3] < 0; + if IsNeg then + Int128ChgSign(FInt); + + {initialize the accumulator to 1.0} + Accum[0] := Int128One_0; + Accum[1] := Int128One_1; + Accum[2] := 0; + Accum[3] := 0; + + {set the bit mask} + Mask := longint($80000000); + + {find the first set bit in the exponent} + while ((N and Mask) = 0) do + Mask := Mask shr 1; + + {calculate the power} + while (Mask <> 0) do begin + Int128Multiply(Accum, Accum); + if ((N and Mask) <> 0) then + Int128Multiply(Accum, FInt); + Mask := Mask shr 1; + end; + + {save the calculated value} + FInt[0] := Accum[0]; + FInt[1] := Accum[1]; + FInt[2] := Accum[2]; + FInt[3] := Accum[3]; + + {force the value negative if required} + if IsNeg and Odd(N) then + Int128ChgSign(FInt); +end; +{--------} +procedure TStDecimal.Round(aRound : TStRoundMethod; aDecPl : integer); +var + IsNeg : boolean; +begin + {check decimal places parameter to be in range} + if not ((0 <= aDecPl) and (aDecPl <= MaxDecPl)) then + raise EStDecMathError.Create(stscDecMathRoundPlacesS); + + {force the value positive} + IsNeg := FInt[3] < 0; + if IsNeg then + Int128ChgSign(FInt); + + {perform the rounding} + Int128Round(FInt, aRound, aDecPl); + + {force the value negative if it was negative} + if IsNeg then + Int128ChgSign(FInt); +end; +{--------} +procedure TStDecimal.SetToOne; +begin + FInt[0] := Int128One_0; + FInt[1] := Int128One_1; + FInt[2] := 0; + FInt[3] := 0; +end; +{--------} +procedure TStDecimal.SetToZero; +begin + FInt[0] := 0; + FInt[1] := 0; + FInt[2] := 0; + FInt[3] := 0; +end; +{--------} +procedure TStDecimal.Subtract(X : TStDecimal); +var + MinusX : TStInt128; +begin + if (X <> nil) then begin + MinusX[0] := X.FInt[0]; + MinusX[1] := X.FInt[1]; + MinusX[2] := X.FInt[2]; + MinusX[3] := X.FInt[3]; + Int128ChgSign(MinusX); + Int128Add(Fint, MinusX); + end; +end; +{--------} +procedure TStDecimal.SubtractOne; +var + MinusOne : TStInt128; +begin + MinusOne[0] := Int128One_0; + MinusOne[1] := Int128One_1; + MinusOne[2] := 0; + MinusOne[3] := 0; + Int128ChgSign(MinusOne); + Int128Add(FInt, MinusOne); +end; +{====================================================================} + +end. diff --git a/components/systools/source/run/stdict.pas b/components/systools/source/run/stdict.pas new file mode 100644 index 000000000..3beb3efd2 --- /dev/null +++ b/components/systools/source/run/stdict.pas @@ -0,0 +1,886 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StDict.pas 4.04 *} +{*********************************************************} +{* SysTools: Dictionary class *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +{Notes: + Nodes stored in the dictionary must be of type TStDictNode. + + Duplicate strings are not allowed in the dictionary. + + Calling Exists moves the found node to the front of its hash bin list. + + Iterate scans the nodes in hash order. + + Hashing and comparison is case-insensitive by default. + + In 16-bit mode, HashSize must be in the range 1..16380. In 32-bit + mode, there is no practical limit on HashSize. A particular value + of HashSize may lead to a better distribution of symbols in the + dictionary, and therefore to better performance. Generally HashSize + should be about the same size as the number of symbols expected in + the dictionary. A prime number tends to give a better distribution. + Based on analysis by D. Knuth, the following values are good + choices for HashSize when the dictionary keys are alphanumeric + strings: + + 59 61 67 71 73 127 131 137 191 193 197 199 251 257 263 311 313 + 317 379 383 389 439 443 449 457 503 509 521 569 571 577 631 641 + 643 647 701 709 761 769 773 823 827 829 839 887 953 967 + + Good values for larger tables can be computed by the GOODHASH.PAS + bonus program. +} + +unit StDict; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils, Classes, + StConst, StBase; + +type + TStDictNode = class(TStNode) +{.Z+} + protected + dnNext : TStDictNode; {Next node in hash list} + dnName : string; {Name of symbol, already a pointer} + function GetName : string; + +{.Z-} + public + constructor CreateStr(const Name : string; AData : Pointer); + {-Initialize node} + destructor Destroy; override; + {-Free name string and destroy node} + + property Name : string + read GetName; + end; + +{.Z+} + TSymbolArray = array[0..(StMaxBlockSize div SizeOf(TStDictNode))-1] of TStDictNode; + PSymbolArray = ^TSymbolArray; +{.Z-} + + TDictHashFunc = + function(const S : AnsiString; Size : Integer) : Integer; + + TStDictionary = class(TStContainer) +{.Z+} + protected + {property instance variables} + FHashSize : Integer; {Bins in symbol array} + FEqual : TStringCompareFunc; {String compare function} + FHash : TDictHashFunc; + + {event variables} + FOnEqual : TStStringCompareEvent; + + {private instance variables} + dySymbols : PSymbolArray; {Pointer to symbol array} + dyIgnoreDups : Boolean; {Ignore duplicates during Join?} + + {protected undocumented methods} + procedure dySetEqual(E : TStringCompareFunc); + procedure dySetHash(H : TDictHashFunc); + procedure dySetHashSize(Size : Integer); + procedure dyFindNode(const Name : string; var H : Integer; + var Prev, This : TStDictNode); +{.Z-} + public + constructor Create(AHashSize : Integer); virtual; + {-Initialize an empty dictionary} + destructor Destroy; override; + {-Destroy a dictionary} + + procedure LoadFromStream(S : TStream); override; + {-Read a dictionary and its data from a stream} + procedure StoreToStream(S : TStream); override; + {-Write a dictionary and its data to a stream} + + procedure Clear; override; + {-Remove all nodes from container but leave it instantiated} + function DoEqual(const String1, String2 : string) : Integer; + virtual; + function Exists(const Name : string; var Data : Pointer) : Boolean; + {-Return True and the Data pointer if Name is in the dictionary} + procedure Add(const Name : string; Data : Pointer); + {-Add new Name and Data to the dictionary} + procedure Delete(const Name : string); + {-Delete a Name from the dictionary} + procedure GetItems(S : TStrings); + {-Fill the string list with all stored strings} + procedure SetItems(S : TStrings); + {-Fill the container with the strings and objects in S} + procedure Update(const Name : string; Data : Pointer); + {-Update the data for an existing element} + function Find(Data : Pointer; var Name : string) : Boolean; + {-Return True and the element Name that matches Data} + + procedure Assign(Source: TPersistent); override; + {-Assign another container's contents to this one} + procedure Join(D : TStDictionary; IgnoreDups : Boolean); + {-Add dictionary D into this one and dispose D} + + function Iterate(Action : TIterateFunc; + OtherData : Pointer) : TStDictNode; + {-Call Action for all the nodes, returning the last node visited} + + function BinCount(H : Integer) : LongInt; + {-Return number of names in a hash bin (for testing)} + + property Equal : TStringCompareFunc + read FEqual + write dySetEqual; + + property Hash : TDictHashFunc + read FHash + write dySetHash; + + property HashSize : Integer + read FHashSize + write dySetHashSize; + + property OnEqual : TStStringCompareEvent + read FOnEqual + write FOnEqual; + end; + + +function AnsiHashText(const S : AnsiString; Size : Integer) : Integer; + {-Case-insensitive hash function that uses the current language driver} +function AnsiHashStr(const S : AnsiString; Size : Integer) : Integer; + {-Case-sensitive hash function} +function AnsiELFHashText(const S : AnsiString; Size : Integer) : Integer; + {-Case-insensitive ELF hash function that uses the current language driver} +function AnsiELFHashStr(const S : AnsiString; Size : Integer) : Integer; + {-Case-sensitive ELF hash function} + + +implementation + +{$IFDEF UNICODE} +uses + AnsiStrings; +{$ENDIF} + +{$IFDEF ThreadSafe} +var + ClassCritSect : TRTLCriticalSection; +{$ENDIF} + +procedure EnterClassCS; +begin +{$IFDEF ThreadSafe} + EnterCriticalSection(ClassCritSect); +{$ENDIF} +end; + +procedure LeaveClassCS; +begin +{$IFDEF ThreadSafe} + LeaveCriticalSection(ClassCritSect); +{$ENDIF} +end; + + +{The following routine was extracted from LockBox and modified} +function HashElf(const Buf; BufSize : LongInt) : LongInt; +var +// Bytes : TByteArray absolute Buf; {!!.02} + Bytes : PAnsiChar; {!!.02} + I, X : LongInt; +begin + Bytes := @Buf; {!!.02} + Result := 0; + for I := 0 to BufSize - 1 do begin + Result := (Result shl 4) + Ord(Bytes^); {!!.02} + Inc(Bytes); {!!.02} + X := LongInt(Result and $F0000000); {!!.02} + if (X <> 0) then + Result := Result xor (X shr 24); + Result := Result and (not X); + end; +end; + +function AnsiELFHashText(const S : AnsiString; Size : Integer) : Integer; +begin + {$IFDEF WStrings} + Result := AnsiELFHashStr(AnsiUpperCaseShort32(S), Size); + {$ELSE} + Result := AnsiELFHashStr(AnsiUpperCase(S), Size); + {$ENDIF} +end; + +function AnsiELFHashStr(const S : AnsiString; Size : Integer) : Integer; +begin + Result := HashElf(S[1], Length(S)) mod Size; + if Result < 0 then + Inc(Result, Size); +end; + +constructor TStDictNode.CreateStr(const Name : string; AData : Pointer); +begin + Create(AData); + dnName := Name; +end; + +destructor TStDictNode.Destroy; +begin + dnName := ''; + inherited Destroy; +end; + +function TStDictNode.GetName : string; +begin + Result := dnName; +end; + +function AnsiHashStr(const S : AnsiString; Size : Integer) : Integer; + {32-bit huge string} +register; +asm + push ebx + push esi + push edi + mov esi,S + mov edi,Size + xor ebx,ebx {ebx will be hash} + or esi,esi {empty literal string comes in as a nil pointer} + jz @2 + mov edx,[esi-4] {edx = length} + or edx,edx {length zero?} + jz @2 + xor ecx,ecx {ecx is shift counter} +@1:xor eax,eax + mov al,[esi] {eax = character} + inc esi + rol eax,cl {rotate character} + xor ebx,eax {xor with hash} + inc ecx {increment shift counter (rol uses only bottom 5 bits)} + dec edx + jnz @1 +@2:mov eax,ebx + xor edx,edx + div edi {edi = Size} + mov eax,edx {return hash mod size} + pop edi + pop esi + pop ebx +end; + +function AnsiHashText(const S : AnsiString; Size : Integer) : Integer; +begin +{$IFDEF WStrings} + Result := AnsiHashStr(AnsiUpperCaseShort32(S), Size); +{$ELSE} + Result := AnsiHashStr(AnsiUpperCase(S), Size); +{$ENDIF} +end; + +function FindNodeData(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; far; +begin + Result := (OtherData <> Node.Data); +end; + +function JoinNode(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; far; +var + H : Integer; + P, T : TStDictNode; +begin + Result := True; + with TStDictionary(OtherData) do begin + dyFindNode(TStDictNode(Node).dnName, H, P, T); + if Assigned(T) then + if dyIgnoreDups then begin + Node.Free; + Exit; + end else + RaiseContainerError(stscDupNode); + T := dySymbols^[H]; + dySymbols^[H] := TStDictNode(Node); + dySymbols^[H].dnNext := T; + Inc(FCount); + end; +end; + +function AssignNode(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; far; + var + DictNode : TStDictNode absolute Node; + OurDict : TStDictionary absolute OtherData; + begin + OurDict.Add(DictNode.Name, DictNode.Data); + Result := true; + end; + +{----------------------------------------------------------------------} + +procedure TStDictionary.Add(const Name : string; Data : Pointer); +var + H : Integer; + P, T : TStDictNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + dyFindNode(Name, H, P, T); + if Assigned(T) then + RaiseContainerError(stscDupNode); + T := dySymbols^[H]; + dySymbols^[H] := TStDictNode.CreateStr(Name, Data); + dySymbols^[H].dnNext := T; + Inc(FCount); +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.Assign(Source: TPersistent); + var + i : integer; + begin + {The only two containers that we allow to be assigned to a string + dictionary are (1) another string dictionary and (2) a Delphi string + list (TStrings)} + if (Source is TStDictionary) then + begin + Clear; + TStDictionary(Source).Iterate(AssignNode, Self); + end + else if (Source is TStrings) then + begin + Clear; + for i := 0 to pred(TStrings(Source).Count) do + Add(TStrings(Source).Strings[i], TStrings(Source).Objects[i]); + end + else + inherited Assign(Source); + end; + +function TStDictionary.BinCount(H : Integer) : LongInt; +var + C : LongInt; + T : TStDictNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + C := 0; + T := dySymbols^[H]; + while Assigned(T) do begin + inc(C); + T := T.dnNext; + end; + Result := C; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.Clear; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if FCount <> 0 then begin + Iterate(DestroyNode, nil); + FCount := 0; + FillChar(dySymbols^, LongInt(FHashSize)*SizeOf(TStDictNode), 0); + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +constructor TStDictionary.Create(AHashSize : Integer); +begin + CreateContainer(TStDictNode, 0); + {FHashSize := 0;} +{$IFDEF WStrings} + FEqual := AnsiCompareTextShort32; +{$ELSE} + FEqual := AnsiCompareText; +{$ENDIF} + FHash := AnsiHashText; + HashSize := AHashSize; +end; + +procedure TStDictionary.Delete(const Name : string); +var + H : Integer; + P, T : TStDictNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + dyFindNode(Name, H, P, T); + if Assigned(T) then begin + if Assigned(P) then + P.dnNext := T.dnNext + else + dySymbols^[H] := T.dnNext; + DestroyNode(Self, T, nil); + Dec(FCount); + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +destructor TStDictionary.Destroy; +begin + if conNodeProt = 0 then + Clear; + if Assigned(dySymbols) then + FreeMem(dySymbols, LongInt(FHashSize)*SizeOf(TStDictNode)); + IncNodeProtection; + inherited Destroy; +end; + +function TStDictionary.DoEqual(const String1, String2 : string) : Integer; +begin + Result := 0; + if Assigned(FOnEqual) then + FOnEqual(Self, String1, String2, Result) + else if Assigned(FEqual) then + Result := FEqual(String1, String2); +end; + +procedure TStDictionary.dyFindNode(const Name : string; var H : Integer; + var Prev, This : TStDictNode); +var + P, T : TStDictNode; +begin + Prev := nil; + This := nil; + H := Hash(Name, HashSize); + T := dySymbols^[H]; + P := nil; + while Assigned(T) do begin + if DoEqual(Name, T.dnName) = 0 then begin + Prev := P; + This := T; + Exit; + end; + P := T; + T := T.dnNext; + end; + + {Not found} + This := nil; +end; + +procedure TStDictionary.dySetEqual(E : TStringCompareFunc); +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if Count = 0 then + FEqual := E; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.dySetHash(H : TDictHashFunc); +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if Count = 0 then + FHash := H; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.dySetHashSize(Size : Integer); +var + H, OldSize : Integer; + TableSize : LongInt; + T, N : TStDictNode; + OldSymbols : PSymbolArray; + OldDisposeData : TDisposeDataProc; + OldOnDisposeData : TStDisposeDataEvent; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + TableSize := LongInt(Size)*SizeOf(TStDictNode); + if (Size <= 0) {or (TableSize > MaxBlockSize)} then + RaiseContainerError(stscBadSize); + + if Size <> FHashSize then begin + OldSymbols := dySymbols; + OldSize := FHashSize; + + {Get a new hash table} + GetMem(dySymbols, TableSize); + FillChar(dySymbols^, TableSize, 0); + FCount := 0; + FHashSize := Size; + + if OldSize <> 0 then begin + {Prevent disposing of the user data while transferring elements} + OldDisposeData := DisposeData; + DisposeData := nil; + OldOnDisposeData := OnDisposeData; + OnDisposeData := nil; + {Add old symbols into new hash table} + for H := 0 to OldSize-1 do begin + T := OldSymbols^[H]; + while Assigned(T) do begin + Add(T.dnName, T.Data); + N := T.dnNext; + {free the node just transferred} + T.Free; + T := N; + end; + end; + {Dispose of old hash table} + FreeMem(OldSymbols, OldSize*SizeOf(TStDictNode)); + {Reassign the dispose data routine} + DisposeData := OldDisposeData; + OnDisposeData := OldOnDisposeData; + end; + + {FHashSize := Size;} + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +function TStDictionary.Exists(const Name : String; var Data : Pointer) : Boolean; +var + H : Integer; + P, T : TStDictNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + dyFindNode(Name, H, P, T); + if Assigned(T) then begin + if Assigned(P) then begin + {Move T to front of list} + P.dnNext := T.dnNext; + T.dnNext := dySymbols^[H]; + dySymbols^[H] := T; + end; + Result := True; + Data := T.Data; + end else + Result := False; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +function TStDictionary.Find(Data : Pointer; var Name : string) : Boolean; +var + T : TStDictNode; +begin + Name := ''; +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + T := Iterate(FindNodeData, Data); + if Assigned(T) then begin + Result := True; + Name := T.dnName; + end else + Result := False; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.GetItems(S : TStrings); +var + H : Integer; + T : TStDictNode; +begin + S.Clear; +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if FCount <> 0 then begin + for H := 0 to FHashSize-1 do begin + T := dySymbols^[H]; + while Assigned(T) do begin + S.AddObject(T.Name, T.Data); + T := T.dnNext; + end; + end; + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.SetItems(S : TStrings); +var + I : Integer; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + Clear; + for I := 0 to S.Count-1 do + Add(S.Strings[I], S.Objects[I]); +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +function TStDictionary.Iterate(Action : TIterateFunc; + OtherData : Pointer) : TStDictNode; +var + H : Integer; + T, N : TStDictNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if FCount <> 0 then begin + for H := 0 to FHashSize-1 do begin + T := dySymbols^[H]; + while Assigned(T) do begin + N := T.dnNext; + if Action(Self, T, OtherData) then + T := N + else begin + Result := T; + Exit; + end; + end; + end; + end; + Result := nil; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.Join(D : TStDictionary; IgnoreDups : Boolean); +begin +{$IFDEF ThreadSafe} + EnterClassCS; + EnterCS; + D.EnterCS; + try +{$ENDIF} + dyIgnoreDups := IgnoreDups; + D.Iterate(JoinNode, Self); + + {Dispose of D, but not its nodes} + D.IncNodeProtection; + D.Free; +{$IFDEF ThreadSafe} + finally + D.LeaveCS; + LeaveCS; + LeaveClassCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.Update(const Name : string; Data : Pointer); +var + H : Integer; + P, T : TStDictNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + dyFindNode(Name, H, P, T); + if Assigned(T) then + T.Data := Data; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.LoadFromStream(S : TStream); +var + Data : pointer; + Reader : TReader; + StreamedClass : TPersistentClass; + StreamedNodeClass : TPersistentClass; + StreamedClassName : string; + StreamedNodeClassName : string; + St : string; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + Clear; + Reader := TReader.Create(S, 1024); + try + with Reader do + begin + StreamedClassName := ReadString; + StreamedClass := GetClass(StreamedClassName); + if (StreamedClass = nil) then + RaiseContainerErrorFmt(stscUnknownClass, [StreamedClassName]); + if (StreamedClass <> Self.ClassType) then + RaiseContainerError(stscWrongClass); + StreamedNodeClassName := ReadString; + StreamedNodeClass := GetClass(StreamedNodeClassName); + if (StreamedNodeClass = nil) then + RaiseContainerErrorFmt(stscUnknownNodeClass, [StreamedNodeClassName]); + if (StreamedNodeClass <> conNodeClass) then + RaiseContainerError(stscWrongNodeClass); + HashSize := ReadInteger; + ReadListBegin; + while not EndOfList do + begin + St := ReadString; + Data := DoLoadData(Reader); + Add(St, Data); + end; + ReadListEnd; + end; + finally + Reader.Free; + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStDictionary.StoreToStream(S : TStream); +var + H : Integer; + Walker : TStDictNode; + Writer : TWriter; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + Writer := TWriter.Create(S, 1024); + try + with Writer do + begin + WriteString(Self.ClassName); + WriteString(conNodeClass.ClassName); + WriteInteger(HashSize); + WriteListBegin; + if (Count <> 0) then + for H := 0 to FHashSize-1 do + begin + Walker := dySymbols^[H]; + while Assigned(Walker) do + begin + WriteString(Walker.dnName); + DoStoreData(Writer, Walker.Data); + Walker := Walker.dnNext; + end; + end; + WriteListEnd; + end; + finally + Writer.Free; + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +{$IFDEF ThreadSafe} +initialization + Windows.InitializeCriticalSection(ClassCritSect); +finalization + Windows.DeleteCriticalSection(ClassCritSect); +{$ENDIF} +end. diff --git a/components/systools/source/run/stexpr.pas b/components/systools/source/run/stexpr.pas new file mode 100644 index 000000000..7d174a356 --- /dev/null +++ b/components/systools/source/run/stexpr.pas @@ -0,0 +1,1660 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StExpr.pas 4.04 *} +{*********************************************************} +{* SysTools: Expression evaluator component *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit StExpr; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, LMessages, + {$ELSE} + Windows, Messages, + {$ENDIF} + Classes, Controls, StdCtrls, SysUtils, + {$IFDEF UseMathUnit} Math, {$ENDIF} + StBase, StConst, StMath; + +type + {TStFloat = Double;} {TStFloat is defined in StBase} + {.Z+} + PStFloat = ^TStFloat; + {.Z-} + +type + {user-defined functions with up to 3 parameters} + TStFunction0Param = + function : TStFloat; + TStFunction1Param = + function(Value1 : TStFloat) : TStFloat; + TStFunction2Param = + function(Value1, Value2 : TStFloat) : TStFloat; + TStFunction3Param = + function(Value1, Value2, Value3 : TStFloat) : TStFloat; + + {user-defined methods with up to 3 parameters} + TStMethod0Param = + function : TStFloat + of object; + TStMethod1Param = + function(Value1 : TStFloat) : TStFloat + of object; + TStMethod2Param = + function(Value1, Value2 : TStFloat) : TStFloat + of object; + TStMethod3Param = + function(Value1, Value2, Value3 : TStFloat) : TStFloat + of object; + + TStGetIdentValueEvent = + procedure(Sender : TObject; const Identifier : String; var Value : TStFloat) + of object; + + {.Z+} + {tokens} + TStToken = ( + ssStart, ssInIdent, ssInNum, ssInSign, ssInExp, ssEol, ssNum, ssIdent, + ssLPar, ssRPar, ssComma, ssPlus, ssMinus, ssTimes, ssDiv, ssEqual, ssPower); + +const + {Note: see Initialization section!} + StExprOperators : array[ssLPar..ssPower] of Char = '(),+-*/=^'; +{$IFNDEF VERSION4} +var + ListSeparator : Char; +{$ENDIF VERSION4} + {.Z-} + +type + TStExpression = class(TStComponent) + {.Z+} + protected {private} + {property variables} + FAllowEqual : Boolean; + FLastError : Integer; + FErrorPos : Integer; + FExpression : String; + + {event variables} + FOnAddIdentifier : TNotifyEvent; + FOnGetIdentValue : TStGetIdentValueEvent; + + {internal variables} + eBusyFlag : Boolean; + eCurChar : Char; + eExprPos : Integer; + eIdentList : TList; + eStack : TList; + eToken : TStToken; + eTokenStr : String; + lhs, rhs : TStFloat; + + {property methods} + function GetAsInteger : Integer; + function GetAsString : String; + + {ident list routines} + function FindIdent(Name : String) : Integer; + + {stack routines} + procedure StackClear; + function StackCount : Integer; + procedure StackPush(const Value : TStFloat); + function StackPeek : TStFloat; + function StackPop : TStFloat; + function StackEmpty : Boolean; + + procedure DoOnAddIdentifier; + procedure GetBase; + {-base: unsigned_num | (expression) | sign factor | func_call } + procedure GetExpression; + {-expression: term | expression+term | expression-term implemented as loop} + procedure GetFactor; + {-factor: base | base^factor} + procedure GetFunction; + {-func_call: identifier | identifier(params)} + procedure GetParams(N : Integer); + {-params: expression | params,expression} + procedure GetTerm; + {-term: factor | term*factor | term/factor implemented as loop} + procedure GetToken; + {-return the next token string in eTokenStr and type in eToken} + function PopOperand : TStFloat; + {-remove top operand value from stack} + procedure RaiseExprError(Code : LongInt; Column : Integer); + {-generate an expression exception} + + public + constructor Create(AOwner : TComponent); + override; + destructor Destroy; + override; + {.Z-} + + function AnalyzeExpression : TStFloat; + procedure AddConstant(const Name : String; Value : TStFloat); + procedure AddFunction0Param(const Name : String; FunctionAddr : TStFunction0Param); + procedure AddFunction1Param(const Name : String; FunctionAddr : TStFunction1Param); + procedure AddFunction2Param(const Name : String; FunctionAddr : TStFunction2Param); + procedure AddFunction3Param(const Name : String; FunctionAddr : TStFunction3Param); + procedure AddInternalFunctions; + procedure AddMethod0Param(const Name : String; MethodAddr : TStMethod0Param); + procedure AddMethod1Param(const Name : String; MethodAddr : TStMethod1Param); + procedure AddMethod2Param(const Name : String; MethodAddr : TStMethod2Param); + procedure AddMethod3Param(const Name : String; MethodAddr : TStMethod3Param); + procedure AddVariable(const Name : String; VariableAddr : PStFloat); + procedure ClearIdentifiers; + procedure GetIdentList(S : TStrings); + procedure RemoveIdentifier(const Name : String); + + {public properties} + property AsInteger : Integer + read GetAsInteger; + property AsFloat : TStFloat + read AnalyzeExpression; + property AsString : String + read GetAsString; + property ErrorPosition : Integer + read FErrorPos; + property Expression : String + read FExpression write FExpression; + property LastError : Integer + read FLastError; + + published + property AllowEqual : Boolean + read FAllowEqual write FAllowEqual default True; + + property OnAddIdentifier : TNotifyEvent + read FOnAddIdentifier write FOnAddIdentifier; + property OnGetIdentValue : TStGetIdentValueEvent + read FOnGetIdentValue write FOnGetIdentValue; + end; + + +type + TStExprErrorEvent = + procedure(Sender : TObject; ErrorNumber : LongInt; const ErrorStr : String) + of object; + +type + TStExpressionEdit = class(TStBaseEdit) + {.Z+} + protected {private} + {property variables} + FAutoEval : Boolean; + FExpr : TStExpression; + FOnError : TStExprErrorEvent; + + {property methods} + function GetOnAddIdentifier : TNotifyEvent; + function GetOnGetIdentValue : TStGetIdentValueEvent; + procedure SetOnAddIdentifier(Value : TNotifyEvent); + procedure SetOnGetIdentValue(Value : TStGetIdentValueEvent); + + {VCL control methods} + procedure CMExit(var Msg : {$IFDEF FPC}TLMessage{$ELSE}TMessage{$ENDIF}); + message CM_EXIT; + + procedure DoEvaluate; + {.Z-} + + protected + procedure KeyPress(var Key: Char); + override; + + public + constructor Create(AOwner : TComponent); + override; + destructor Destroy; + override; + + function Evaluate : TStFloat; + + property Expr : TStExpression + read FExpr; + + published + property AutoEval : Boolean + read FAutoEval write FAutoEval default False; + + property OnAddIdentifier : TNotifyEvent + read GetOnAddIdentifier write SetOnAddIdentifier; + property OnError : TStExprErrorEvent + read FOnError write FOnError; + property OnGetIdentValue : TStGetIdentValueEvent + read GetOnGetIdentValue write SetOnGetIdentValue; + end; + +function AnalyzeExpr(const Expr : String) : Double; + {-Compute the arithmetic expression Expr and return the result} + +procedure TpVal(const S : String; var V : TStFloat{Extended}; var Code : Integer); +{ +Evaluate string as a floating point number, emulates Borlandish Pascal's +Val() intrinsic +} + + +implementation + +const + Alpha = ['A'..'Z', 'a'..'z', '_']; + { Numeric = ['0'..'9', '.']; } + AlphaNumeric = Alpha + ['0'..'9']; +var + {Note: see Initialization section!} + Numeric: set of Ansichar; + +type + PStIdentRec = ^TStIdentRec; + {a double-variant record - wow - confusing maybe, but it saves space} + TStIdentRec = record + Name : String; + Kind : (ikConstant, ikVariable, ikFunction, ikMethod); + case Byte of + 0 : (Value : TStFloat); + 1 : (VarAddr : PStFloat); + 2 : (PCount : Integer; + case Byte of + 0 : (Func0Addr : TStFunction0Param); + 1 : (Func1Addr : TStFunction1Param); + 2 : (Func2Addr : TStFunction2Param); + 3 : (Func3Addr : TStFunction3Param); + 4 : (Meth0Addr : TStMethod0Param); + 5 : (Meth1Addr : TStMethod1Param); + 6 : (Meth2Addr : TStMethod2Param); + 7 : (Meth3Addr : TStMethod3Param); + ) + end; + + +{routine for backward compatibility} + +function AnalyzeExpr(const Expr : String) : Double; +begin + with TStExpression.Create(nil) do + try + Expression := Expr; + Result := AnalyzeExpression; + finally + Free; + end; +end; + + +{*** function definitions ***} + +function _Abs(Value : TStFloat) : TStFloat; far; +begin + Result := Abs(Value); +end; + +function _ArcTan(Value : TStFloat) : TStFloat; far; +begin + Result := ArcTan(Value); +end; + +function _Cos(Value : TStFloat) : TStFloat; far; +begin + Result := Cos(Value); +end; + +function _Exp(Value : TStFloat) : TStFloat; far; +begin + Result := Exp(Value); +end; + +function _Frac(Value : TStFloat) : TStFloat; far; +begin + Result := Frac(Value); +end; + +function _Int(Value : TStFloat) : TStFloat; far; +begin + Result := Int(Value); +end; + +function _Trunc(Value : TStFloat) : TStFloat; far; +begin + Result := Trunc(Value); +end; + +function _Ln(Value : TStFloat) : TStFloat; far; +begin + Result := Ln(Value); +end; + +function _Pi : TStFloat; far; +begin + Result := Pi; +end; + +function _Round(Value : TStFloat) : TStFloat; far; +begin + Result := Round(Value); +end; + +function _Sin(Value : TStFloat) : TStFloat; far; +begin + Result := Sin(Value); +end; + +function _Sqr(Value : TStFloat) : TStFloat; far; +begin + Result := Sqr(Value); +end; + +function _Sqrt(Value : TStFloat) : TStFloat; far; +begin + Result := Sqrt(Value); +end; + +{$IFDEF UseMathUnit} +function _ArcCos(Value : TStFloat) : TStFloat; far; +begin + Result := ArcCos(Value); +end; + +function _ArcSin(Value : TStFloat) : TStFloat; far; +begin + Result := ArcSin(Value); +end; + +function _ArcTan2(Value1, Value2 : TStFloat) : TStFloat; far; +begin + Result := ArcTan2(Value1, Value2); +end; + +function _Tan(Value : TStFloat) : TStFloat; far; +begin + Result := Tan(Value); +end; + +function _Cotan(Value : TStFloat) : TStFloat; far; +begin + Result := CoTan(Value); +end; + +function _Hypot(Value1, Value2 : TStFloat) : TStFloat; far; +begin + Result := Hypot(Value1, Value2); +end; + +function _Cosh(Value : TStFloat) : TStFloat; far; +begin + Result := Cosh(Value); +end; + +function _Sinh(Value : TStFloat) : TStFloat; far; +begin + Result := Sinh(Value); +end; + +function _Tanh(Value : TStFloat) : TStFloat; far; +begin + Result := Tanh(Value); +end; + +function _ArcCosh(Value : TStFloat) : TStFloat; far; +begin + Result := ArcCosh(Value); +end; + +function _ArcSinh(Value : TStFloat) : TStFloat; far; +begin + Result := ArcSinh(Value); +end; + +function _ArcTanh(Value : TStFloat) : TStFloat; far; +begin + Result := ArcTanh(Value); +end; + +function _Lnxp1(Value : TStFloat) : TStFloat; far; +begin + Result := Lnxp1(Value); +end; + +function _Log10(Value : TStFloat) : TStFloat; far; +begin + Result := Log10(Value); +end; + +function _Log2(Value : TStFloat) : TStFloat; far; +begin + Result := Log2(Value); +end; + +function _LogN(Value1, Value2 : TStFloat) : TStFloat; far; +begin + Result := LogN(Value1, Value2); +end; + +function _Ceil(Value : TStFloat) : TStFloat; far; +begin + Result := Ceil(Value); +end; + +function _Floor(Value : TStFloat) : TStFloat; far; +begin + Result := Floor(Value); +end; +{$ENDIF} + + +{*** TStExpression ***} + +procedure TStExpression.AddConstant(const Name : String; Value : TStFloat); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.Kind := ikConstant; + IR^.Value := Value; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddFunction0Param(const Name : String; + FunctionAddr : TStFunction0Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 0; + IR^.Kind := ikFunction; + IR^.Func0Addr := FunctionAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddFunction1Param(const Name : String; + FunctionAddr : TStFunction1Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 1; + IR^.Kind := ikFunction; + IR^.Func1Addr := FunctionAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddFunction2Param(const Name : String; + FunctionAddr : TStFunction2Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 2; + IR^.Kind := ikFunction; + IR^.Func2Addr := FunctionAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddFunction3Param(const Name : String; + FunctionAddr : TStFunction3Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 3; + IR^.Kind := ikFunction; + IR^.Func3Addr := FunctionAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddInternalFunctions; +begin + eBusyFlag := True; + try + {add function name and parameter count to list} + AddFunction1Param('abs', _Abs); + AddFunction1Param('arctan', _ArcTan); + AddFunction1Param('cos', _Cos); + AddFunction1Param('exp', _Exp); + AddFunction1Param('frac', _Frac); + AddFunction1Param('int', _Int); + AddFunction1Param('trunc', _Trunc); + AddFunction1Param('ln', _Ln); + AddFunction0Param('pi', _Pi); + AddFunction1Param('round', _Round); + AddFunction1Param('sin', _Sin); + AddFunction1Param('sqr', _Sqr); + AddFunction1Param('sqrt', _Sqrt); + {$IFDEF UseMathUnit} + AddFunction1Param('arccos', _ArcCos); + AddFunction1Param('arcsin', _ArcSin); + AddFunction2Param('arctan2', _ArcTan2); + AddFunction1Param('tan', _Tan); + AddFunction1Param('cotan', _Cotan); + AddFunction2Param('hypot', _Hypot); + AddFunction1Param('cosh', _Cosh); + AddFunction1Param('sinh', _Sinh); + AddFunction1Param('tanh', _Tanh); + AddFunction1Param('arccosh', _ArcCosh); + AddFunction1Param('arcsinh', _ArcSinh); + AddFunction1Param('arctanh', _ArcTanh); + AddFunction1Param('lnxp1', _Lnxp1); + AddFunction1Param('log10', _Log10); + AddFunction1Param('log2', _Log2); + AddFunction2Param('logn', _LogN); + AddFunction1Param('ceil', _Ceil); + AddFunction1Param('floor', _Floor); + {$ENDIF} + finally + eBusyFlag := False; + end; +end; + +procedure TStExpression.AddMethod0Param(const Name : String; + MethodAddr : TStMethod0Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 0; + IR^.Kind := ikMethod; + IR^.Meth0Addr := MethodAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddMethod1Param(const Name : String; + MethodAddr : TStMethod1Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 1; + IR^.Kind := ikMethod; + IR^.Meth1Addr := MethodAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddMethod2Param(const Name : String; + MethodAddr : TStMethod2Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 2; + IR^.Kind := ikMethod; + IR^.Meth2Addr := MethodAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddMethod3Param(const Name : String; + MethodAddr : TStMethod3Param); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.PCount := 3; + IR^.Kind := ikMethod; + IR^.Meth3Addr := MethodAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +procedure TStExpression.AddVariable(const Name : String; VariableAddr : PStFloat); +var + IR : PStIdentRec; +begin + if FindIdent(Name) > -1 then + RaiseExprError(stscExprDupIdent, 0); + + New(IR); + IR^.Name := LowerCase(Name); + IR^.Kind := ikVariable; + IR^.VarAddr := VariableAddr; + eIdentList.Add(IR); + + DoOnAddIdentifier; +end; + +function TStExpression.AnalyzeExpression : TStFloat; +begin + FLastError := 0; + + {error if nothing to do} + if (Length(FExpression) = 0) then + RaiseExprError(stscExprEmpty, 0); + + {clear operand stack} + StackClear; + + {get the first character from the string} + eExprPos := 1; + eCurChar := FExpression[1]; + + {get the first Token and start parsing} + GetToken; + GetExpression; + + {make sure expression is fully evaluated} + if (eToken <> ssEol) or (StackCount <> 1) then + RaiseExprError(stscExprBadExp, FErrorPos); + + Result := StackPop; +end; + +procedure TStExpression.ClearIdentifiers; +var + I : Integer; +begin + for I := 0 to eIdentList.Count-1 do + Dispose(PStIdentRec(eIdentList[I])); + eIdentList.Clear; +end; + +constructor TStExpression.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + eStack := TList.Create; + eIdentList := TList.Create; + + FAllowEqual := True; + + AddInternalFunctions; +end; + +destructor TStExpression.Destroy; +begin + StackClear; + eStack.Free; + eStack := nil; + + ClearIdentifiers; + eIdentList.Free; + eIdentList := nil; + + inherited Destroy; +end; + +procedure TStExpression.DoOnAddIdentifier; +begin + if eBusyFlag then + Exit; + if Assigned(FOnAddIdentifier) then + FOnAddIdentifier(Self); +end; + +function TStExpression.FindIdent(Name : String) : Integer; +var + I : Integer; +begin + Result := -1; + for I := 0 to eIdentList.Count-1 do begin + if Name = PStIdentRec(eIdentList[I])^.Name then begin + Result := I; + Break; + end; + end; +end; + +function TStExpression.GetAsInteger : Integer; +begin + Result := Round(AnalyzeExpression); +end; + +function TStExpression.GetAsString : String; +begin + Result := FloatToStr(AnalyzeExpression); +end; + +procedure TpVal(const S : String; var V : TStFloat{Extended}; var Code : Integer); +{ +Evaluate string as a floating point number, emulates Borlandish Pascal's +Val() intrinsic + +Recognizes strings of the form: +[-/+](d*[.][d*]|[d*].d*)[(e|E)[-/+](d*)] + +Parameters: + S : string to convert + V : Resultant Extended value + Code: position in string where an error occured or + -- 0 if no error + -- Length(S) + 1 if otherwise valid string terminates prematurely (e.g. "10.2e-") + + if Code <> 0 on return then the value of V is undefined +} + +type + { recognizer machine states } + TNumConvertState = (ncStart, ncSign, ncWhole, ncDecimal, ncStartDecimal, + ncFraction, ncE, ncExpSign, ncExponent, ncEndSpaces, ncBadChar); +const + { valid stop states for machine } + StopStates: set of TNumConvertState = [ncWhole, ncDecimal, ncFraction, + ncExponent, ncEndSpaces]; + +var + i : Integer; { general purpose counter } + P : PChar; { current position in evaluated string } + NegVal : Boolean; { is entire value negative? } + NegExp : Boolean; { is exponent negative? } + Exponent : LongInt; { accumulator for exponent } + Mantissa : Extended; { mantissa } + FracMul : Extended; { decimal place holder } + State : TNumConvertState; { current state of recognizer machine } + + +begin +{initializations} + V := 0.0; + Code := 0; + + State := ncStart; + + NegVal := False; + NegExp := False; + + Mantissa := 0.0; + FracMul := 0.1; + Exponent := 0; + +{ +Evaluate the string +When the loop completes (assuming no error) + -- WholeVal will contain the absolute value of the mantissa + -- Exponent will contain the absolute value of the exponent + -- NegVal will be set True if the mantissa is negative + -- NegExp will be set True if the exponent is negative + +If an error occurs P will be pointing at the character that caused the problem, +or one past the end of the string if it terminates prematurely +} + + { keep going until run out of string or halt if unrecognized or out-of-place + character detected } + + P := PChar(S); + for i := 1 to Length(S) do begin + case State of + ncStart : begin + if P^ = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator then begin + State := ncStartDecimal; { decimal point detected in mantissa } + end else + + case P^ of + ' ': begin + {ignore} + end; + + '+': begin + State := ncSign; + end; + + '-': begin + NegVal := True; + State := ncSign; + end; + + 'e', 'E': begin + Mantissa := 0; + State := ncE; { exponent detected } + end; + + '0'..'9': begin + State := ncWhole; { start of whole portion of mantissa } + Mantissa := (Mantissa * 10) + (Ord(P^) - Ord('0')); + end; + + else + State := ncBadChar; + end; + + end; + + ncSign : begin + if P^ = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator then begin + State := ncDecimal; { decimal point detected in mantissa } + end else + + case P^ of + '0'..'9': begin + State := ncWhole; { start of whole portion of mantissa } + Mantissa := (Mantissa * 10) + (Ord(P^) - Ord('0')); + end; + + 'e', 'E': begin + Mantissa := 0; + State := ncE; { exponent detected } + end; + + else + State := ncBadChar; + end; + end; + + ncWhole : begin + if P^ = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator then begin + State := ncDecimal; { decimal point detected in mantissa } + end else + + case P^ of + '0'..'9': begin + Mantissa := (Mantissa * 10) + (Ord(P^) - Ord('0')); + end; + + '.': begin + end; + + 'e', 'E': begin + State := ncE; { exponent detected } + end; + + ' ': begin + State := ncEndSpaces; + end; + + else + State := ncBadChar; + end; + end; + + ncDecimal : begin + case P^ of + '0'..'9': begin + State := ncFraction; { start of fractional portion of mantissa } + Mantissa := Mantissa + (FracMul * (Ord(P^) - Ord('0'))); + FracMul := FracMul * 0.1; + end; + + 'e', 'E': begin + State := ncE; { exponent detected } + end; + + ' ': begin + State := ncEndSpaces; + end; + + else + State := ncBadChar; + end; + + end; + + ncStartDecimal : begin + case P^ of + '0'..'9': begin + State := ncFraction; { start of fractional portion of mantissa } + Mantissa := Mantissa + (FracMul * (Ord(P^) - Ord('0'))); + FracMul := FracMul * 0.1; + end; + + ' ': begin + State := ncEndSpaces; + end; + + else + State := ncBadChar; + end; + end; + + ncFraction : begin + case P^ of + '0'..'9': begin + Mantissa := Mantissa + (FracMul * (Ord(P^) - Ord('0'))); + FracMul := FracMul * 0.1; + end; + + 'e', 'E': begin + State := ncE; { exponent detected } + end; + + ' ': begin + State := ncEndSpaces; + end; + + else + State := ncBadChar; + end; + end; + + ncE : begin + case P^ of + '0'..'9': begin + State := ncExponent; { start of exponent } + Exponent := Exponent * 10 + (Ord(P^) - Ord('0')); + end; + + '+': begin + State := ncExpSign; + end; + + '-': begin + NegExp := True; { exponent is negative } + State := ncExpSign; + end; + + else + State := ncBadChar; + end; + end; + + ncExpSign : begin + case P^ of + '0'..'9': begin + State := ncExponent; { start of exponent } + Exponent := Exponent * 10 + (Ord(P^) - Ord('0')); + end; + + else + State := ncBadChar; + end; + end; + + ncExponent : begin + case P^ of + '0'..'9': begin + Exponent := Exponent * 10 + (Ord(P^) - Ord('0')); + end; + + ' ': begin + State := ncEndSpaces; + end; + + else + State := ncBadChar; + end; + end; + + ncEndSpaces : begin + case P^ of + ' ': begin + {ignore} + end; + else + State := ncBadChar; + end; + end; + end; + + Inc(P); + if State = ncBadChar then begin + Code := i; + Break; + end; + end; +{ +Final calculations +} + if not (State in StopStates) then begin + Code := i; { point to error } + end else begin + { negate if needed } + if NegVal then + Mantissa := -Mantissa; + + + { apply exponent if any } + if Exponent <> 0 then begin + if NegExp then + for i := 1 to Exponent do + Mantissa := Mantissa * 0.1 + else + for i := 1 to Exponent do + Mantissa := Mantissa * 10.0; + end; + + V := Mantissa; + end; +end; + + +procedure TStExpression.GetBase; +var + SaveSign : TStToken; + Code : Integer; + NumVal : TStFloat; +begin + case eToken of + ssNum : + begin + {evaluate real number string} + if (eTokenStr[1] = {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator{'.'}) then + eTokenStr := '0' + eTokenStr; + {Val(eTokenStr, NumVal, Code);} + TpVal(eTokenStr, NumVal, Code); + if Code <> 0 then + RaiseExprError(stscExprBadNum, FErrorPos); + {put on operand stack} + StackPush(NumVal); + GetToken; + end; + ssIdent : + {function call} + GetFunction; + ssLPar : + begin + {nested expression} + GetToken; + GetExpression; + if (eToken <> ssRPar) then + RaiseExprError(stscExprBadExp, FErrorPos); + GetToken; + end; + ssPlus, ssMinus : + begin + {unary sign} + SaveSign := eToken; + GetToken; + GetFactor; + if (SaveSign = ssMinus) then + {update operand stack} + StackPush(-PopOperand); + end; + else + RaiseExprError(stscExprOpndExp, FErrorPos); + end; +end; + +procedure TStExpression.GetExpression; +var + SaveOp : TStToken; +begin + GetTerm; + while (True) do begin + case eToken of + ssPlus, ssMinus : + begin + SaveOp := eToken; + GetToken; + GetTerm; + rhs := PopOperand; + lhs := PopOperand; + try + case SaveOp of + ssPlus : StackPush(lhs+rhs); + ssMinus : StackPush(lhs-rhs); + end; + except + {note operand stack overflow not possible here} + RaiseExprError(stscExprNumeric, FErrorPos); + end; + end; + else + Break; + end; + end; +end; + +procedure TStExpression.GetFactor; +begin + GetBase; + if (eToken = ssPower) then begin + GetToken; + GetFactor; + rhs := PopOperand; + lhs := PopOperand; + try + StackPush(Power(lhs, rhs)); + except + {note operand stack overflow not possible here} + RaiseExprError(stscExprNumeric, FErrorPos); + end; + end; +end; + +procedure TStExpression.GetFunction; +var + I : Integer; + P1, P2, P3 : TStFloat; + Ident : PStIdentRec; + St : String; +begin + St := eTokenStr; + GetToken; + + {is this a request to add a constant? (=)} + if FAllowEqual and (eTokenStr = '=') then begin + GetToken; + GetExpression; + {leave result on the stack to be returned as the expression result} + AddConstant(St, StackPeek); + Exit; + end; + + I := FindIdent(St); + if I > -1 then begin + Ident := eIdentList[I]; + case Ident^.Kind of + ikConstant : StackPush(Ident^.Value); + ikVariable : StackPush(PStFloat(Ident^.VarAddr)^); + ikFunction : + begin + {place parameters on stack, if any} + GetParams(Ident^.PCount); + try + case Ident^.PCount of + 0 : StackPush(TStFunction0Param(Ident^.Func0Addr)); + 1 : begin + P1 := PopOperand; + StackPush(TStFunction1Param(Ident^.Func1Addr)(P1)); + end; + 2 : begin + P2 := PopOperand; + P1 := PopOperand; + StackPush(TStFunction2Param(Ident^.Func2Addr)(P1, P2)); + end; + 3 : begin + P3 := PopOperand; + P2 := PopOperand; + P1 := PopOperand; + StackPush(TStFunction3Param(Ident^.Func3Addr)(P1, P2, P3)); + end; + else + RaiseExprError(stscExprNumeric, FErrorPos); + end; + except + {note operand stack overflow or underflow not possible here} + {translate RTL numeric errors into STEXPR error} + RaiseExprError(stscExprNumeric, FErrorPos); + end; + end; + ikMethod : + begin + {place parameters on stack, if any} + GetParams(Ident^.PCount); + try + case Ident^.PCount of + 0 : StackPush(TStMethod0Param(Ident^.Meth0Addr)); + 1 : begin + P1 := PopOperand; + StackPush(TStMethod1Param(Ident^.Meth1Addr)(P1)); + end; + 2 : begin + P2 := PopOperand; + P1 := PopOperand; + StackPush(TStMethod2Param(Ident^.Meth2Addr)(P1, P2)); + end; + 3 : begin + P3 := PopOperand; + P2 := PopOperand; + P1 := PopOperand; + StackPush(TStMethod3Param(Ident^.Meth3Addr)(P1, P2, P3)); + end; + else + RaiseExprError(stscExprNumeric, FErrorPos); + end; + except + {note operand stack overflow or underflow not possible here} + {translate RTL numeric errors into STEXPR error} + RaiseExprError(stscExprNumeric, FErrorPos); + end; + end; + end; + end else begin + + if Assigned(FOnGetIdentValue) then begin + P1 := 0; + FOnGetIdentValue(Self, St, P1); + StackPush(P1); + end else + RaiseExprError(stscExprUnkFunc, FErrorPos); + end; +end; + +procedure TStExpression.GetIdentList(S : TStrings); +var + I : Integer; +begin + if Assigned(S) then begin + S.Clear; + for I := 0 to eIdentList.Count-1 do + S.Add(PStIdentRec(eIdentList[I])^.Name); + end; +end; + +procedure TStExpression.GetParams(N : Integer); +begin + if (N > 0) then begin + if (eToken <> ssLPar) then + RaiseExprError(stscExprLParExp, FErrorPos); + while (N > 0) do begin + GetToken; + {evaluate parameter value and leave on stack} + GetExpression; + Dec(N); + if (N > 0) then + if (eToken <> ssComma) then + RaiseExprError(stscExprCommExp, FErrorPos); + end; + if (eToken <> ssRPar) then + RaiseExprError(stscExprRParExp, FErrorPos); + GetToken; + end; +end; + +procedure TStExpression.GetTerm; +var + SaveOp : TStToken; +begin + GetFactor; + while (True) do begin + case eToken of + ssTimes, ssDiv : + begin + SaveOp := eToken; + GetToken; + GetFactor; + rhs := PopOperand; + lhs := PopOperand; + try + case SaveOp of + ssTimes : + StackPush(lhs*rhs); + ssDiv : + StackPush(lhs/rhs); + end; + except + {note operand stack overflow not possible here} + RaiseExprError(stscExprNumeric, FErrorPos); + end; + end; + else + break; + end; + end; +end; + +procedure TStExpression.GetToken; +var + Done : Boolean; + TT : TStToken; +begin + eToken := ssStart; + eTokenStr := ''; + Done := False; + + while (not Done) do begin + case eToken of + ssStart : + begin + {save potential error column at start of eTokenStr} + FErrorPos := eExprPos; + if (eCurChar = ' ') or (eCurChar = ^I) then + {skip leading whitespace} + else if (eCurChar = #0) then begin + {end of string} + eToken := ssEol; + Done := true; + end else if (eCurChar in Alpha) then begin + {start of identifier} + eTokenStr := eTokenStr + LowerCase(eCurChar); + eToken := ssInIdent; + end else if (eCurChar in Numeric) then begin + {start of value} + eTokenStr := eTokenStr + eCurChar; + eToken := ssInNum; + end else begin + {presumably a single character operator} + eTokenStr := eTokenStr + eCurChar; + {make sure it matches a known operator} + for TT := ssLPar to ssPower do + if (eCurChar = StExprOperators[TT]) then begin + Done := True; + eToken := TT; + Break; + end; + if (not Done) then begin + {error: unknown character} + RaiseExprError(stscExprBadChar, FErrorPos); + end; + {move to next character} + Inc(eExprPos); + if (eExprPos > Length(FExpression)) then + eCurChar := #0 + else + eCurChar := FExpression[eExprPos]; + end; + end; + ssInIdent : + if (eCurChar in AlphaNumeric) then + {continuing in identifier} + eTokenStr := eTokenStr + LowerCase(eCurChar) + else begin + {end of identifier} + eToken := ssIdent; + Done := True; + end; + ssInNum : + if (eCurChar in Numeric) then + {continuing in number} + eTokenStr := eTokenStr + eCurChar + else if (LowerCase(eCurChar) = 'e') then begin + {start of exponent} + eTokenStr := eTokenStr + LowerCase(eCurChar); + eToken := ssInSign; + end else begin + {end of number} + eToken := ssNum; + Done := True; + end; + ssInSign : + if (eCurChar in ['-', '+']) or (eCurChar in Numeric) then begin + {have exponent sign or start of number} + eTokenStr := eTokenStr + eCurChar; + eToken := ssInExp; + end else begin + {error: started exponent but didn't finish} + RaiseExprError(stscExprBadNum, FErrorPos); + end; + ssInExp : + if (eCurChar in Numeric) then + {continuing in number} + eTokenStr := eTokenStr + eCurChar + else begin + {end of number} + eToken := ssNum; + Done := True; + end; + end; + + {get next character} + if (not Done) then begin + Inc(eExprPos); + if (eExprPos > Length(FExpression)) then + eCurChar := #0 + else + eCurChar := FExpression[eExprPos]; + end; + + end; +end; + +function TStExpression.PopOperand : TStFloat; +begin + if StackEmpty then + RaiseExprError(stscExprBadExp, FErrorPos); + Result := StackPop; +end; + +procedure TStExpression.RaiseExprError(Code : LongInt; Column : Integer); +var + E : EStExprError; +begin + {clear operand stack} + StackClear; + FLastError := Code; + E := EStExprError.CreateResTPCol(Code, Column, 0); + E.ErrorCode := Code; + raise E; +end; + +procedure TStExpression.RemoveIdentifier(const Name : String); +var + I : Integer; + S : String; +begin + S := LowerCase(Name); + I := FindIdent(S); + if I > -1 then begin + Dispose(PStIdentRec(eIdentList[I])); + eIdentList.Delete(I); + end; +end; + +procedure TStExpression.StackClear; +var + I : Integer; +begin + for I := 0 to eStack.Count-1 do + Dispose(PStFloat(eStack[I])); + eStack.Clear; +end; + +function TStExpression.StackCount : Integer; +begin + Result := eStack.Count; +end; + +function TStExpression.StackEmpty : Boolean; +begin + Result := eStack.Count = 0; +end; + +function TStExpression.StackPeek : TStFloat; +begin + Result := PStFloat(eStack[eStack.Count-1])^; +end; + +function TStExpression.StackPop : TStFloat; +var + PF : PStFloat; +begin + PF := PStFloat(eStack[eStack.Count-1]); + Result := PF^; + Dispose(PF); + eStack.Delete(eStack.Count-1); +end; + +procedure TStExpression.StackPush(const Value : TStFloat); +var + PF : PStFloat; +begin + New(PF); + PF^ := Value; + try + eStack.Add(PF); + except + Dispose(PF); + raise; + end; +end; + + +{*** TStExpressionEdit ***} + +procedure TStExpressionEdit.CMExit( + var Msg : {$IFDEF FPC}TLMessage{$ELSE}TMessage{$ENDIF}); +begin + inherited; + + if FAutoEval then begin + try + DoEvaluate; + except + SetFocus; + raise; + end; + end; +end; + +constructor TStExpressionEdit.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + FExpr := TStExpression.Create(Self); + FAutoEval := False; +end; + +destructor TStExpressionEdit.Destroy; +begin + FExpr.Free; + + inherited Destroy; +end; + +procedure TStExpressionEdit.DoEvaluate; +var + V : TStFloat; +begin + if Text > '' then begin + V := Evaluate; + if FExpr.FLastError = 0 then + Text := FloatToStr(V) + else + SelStart := FExpr.FErrorPos; + end else + Text := '0'; +end; + +function TStExpressionEdit.Evaluate : TStFloat; +begin + Result := 0; + FExpr.Expression := Text; + try + Result := FExpr.AnalyzeExpression; + except + on E : EStExprError do begin + SelStart := FExpr.FErrorPos; + if Assigned(FOnError) then + FOnError(Self, E.ErrorCode, E.Message) + else + raise; + end else + raise; + end; +end; + +function TStExpressionEdit.GetOnAddIdentifier : TNotifyEvent; +begin + Result := FExpr.OnAddIdentifier; +end; + +function TStExpressionEdit.GetOnGetIdentValue : TStGetIdentValueEvent; +begin + Result := FExpr.OnGetIdentValue; +end; + +procedure TStExpressionEdit.KeyPress(var Key : Char); +begin + if Key = #13 then begin + DoEvaluate; + Key := #0; + SelStart := Length(Text); + end; + + inherited KeyPress(Key); +end; + +procedure TStExpressionEdit.SetOnAddIdentifier(Value : TNotifyEvent); +begin + FExpr.OnAddIdentifier := Value; +end; + +procedure TStExpressionEdit.SetOnGetIdentValue(Value : TStGetIdentValueEvent); +begin + FExpr.OngetIdentValue := Value; +end; + +{$IFNDEF FPC} +procedure GetListSep; +{$IFNDEF VERSION4} +var + SepBuf : array[0..1] of Char; +begin + if GetLocaleInfo(GetThreadLocale, LOCALE_SLIST, SepBuf, Length(SepBuf)) > 0 then + ListSeparator := SepBuf[0] + else + ListSeparator := ','; +end; +{$ENDIF VERSION4} +{$ENDIF} + +initialization +{$IFDEF FPC} + ListSeparator := FormatSettings.ListSeparator; + Numeric := ['0'..'9', FormatSettings.DecimalSeparator]; + StExprOperators[ssComma] := FormatSettings.ListSeparator; +{$ELSE} + {$IFNDEF VERSION4} + GetListSep; + {$ENDIF VERSION4} + Numeric := ['0'..'9', {'.'}{$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator]; + StExprOperators[ssComma] := {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}ListSeparator; + {$ENDIF} +end. + diff --git a/components/systools/source/run/stexpr.txt b/components/systools/source/run/stexpr.txt new file mode 100644 index 000000000..4590205f3 --- /dev/null +++ b/components/systools/source/run/stexpr.txt @@ -0,0 +1,355 @@ + +This file documents the TStExpression and TStExpressionEdit components. + + +TStExpression +============= + +TStExpression is a non-visual component that provides expression evaluation +at several different levels. At the lowest level, simple mathematical +expressions can be evaluated and the resulting value obtained. On a higher +level, you can define alpha-numeric constants that can then be used within +expressions; You can add user-defined functions (and even methods of a class) +so that the names of these routines can be used in expressions; You can +define variables that relate directly to variables in your program and even +use them in expressions. + +Note: TStExpression replaces AnalyzeExpr that SysTools version 2.00 provided, +but a version of that routine is still provided for backward compatibility. + +The TStExpression expression parser implements the following grammar, similar +to a subset of Pascal: + + expression: term | expression+term | expression-term + term: factor | term*factor | term/factor + factor: base | base^factor + base: unsigned_num | (expression) | sign factor | func_call + unsigned_num: digit_seq | digit_seq.digit_seq | digit_seq scale_fac | + digit_seq.digit_seq scale_fac + sign: + | - + func_call: identifier | identifier(params) + params: expression | params,expression + scale_fac: E digit_seq | E sign digit_seq + digit_seq: digit | digit_seq digit + identifier: starts with A..Z,_ continues with A..Z,_,0..9 + digit: 0..9 + +Case is not significant when matching characters. + +The grammar follows normal rules of arithmetic precedence, with ^ highest, * +and / in the middle, and + and - lowest. Thus, 1+2*3^4 means 1+(2*(3^4)). +Parentheses can be used to force non-default precedence. + +Note that the power operator x^y is right-associative. This means that +2^0.5^2 is equivalent to 2^(0.5^2). All other arithmetic operators are left +associative: 1-2-3 is equivalent to (1-2)-3. + +The following functions are supported in 16-bit and 32-bit applications: + + abs, arctan, cos, exp, frac, int(trunc), ln, pi, round, sin, sqr, + sqrt + +If the VCL Math unit is available and you define the "UseMathUnit" define in +STDEFINE.INC, the following are also available: + + arccos, arcsin, arctan2, tan, cotan, hypot, cosh, sinh, tanh, + arccosh, arcsinh, arctanh, lnxp1, log10, log2, logn, ceil, floor + +The calling conventions for all functions match those of the VCL runtime +library or Math unit. The acceptable parameter ranges and output values also +match thoses of the VCL runtime library or MATH unit. + +When the input expression contains an error, TStExpression raises an +exception of type EStExprError. Its ErrorCode property provides more detail +about the error. Its ErrorColumn property gives the string index of the start +of the token where the error was detected. + +TStExpression is very flexible. You can add support for your own functions +easily. For example, to add support for the Sin() function, first write a +function to provide the proper number and type of parameters (the "far" can +be omitted with 32-bit compilers): + +function _Sin(Value : TStFloat) : TStFloat; far; +begin + Result := Sin(Value); +end; + +and then add it to the TStExpression component: + + MyStExpression.AddFunction1Param('sin', _Sin); + +Or, if you wanted to use a method of the form (or any other class) that you +were working in, you could do the same thing this way: + +function MyForm._Sin(Value : TStFloat) : TStFloat; +begin + Result := Sin(Value); +end; + +and then add it to the TStExpression component: + + MyStExpression.AddMethod1Param('sin', _Sin); + +TStExpression supports user-defined functions with 0 to 3 parameters. The +parameters and function result must be the TStFloat type (defined in the +STBASE unit). In the example above, that's why we didn't just add +the Sin() function directly, in the call to AddFunction1Param -- The +TStExpression component must know the data types of parameters and return +values. If the function you are adding has no parameters, use the +AddFunction0Parm() method. AddFunction2Param for functions with two +parameters, etc. + +The following function and method types define all possible user-defined +function and method types accepted by the TStExpression component: + + {user-defined functions with up to 3 parameters} + TStFunction0Param = + function : TStFloat; + TStFunction1Param = + function(Value1 : TStFloat) : TStFloat; + TStFunction2Param = + function(Value1, Value2 : TStFloat) : TStFloat; + TStFunction3Param = + function(Value1, Value2, Value3 : TStFloat) : TStFloat; + + {user-defined methods with up to 3 parameters} + TStMethod0Param = + function : TStFloat + of object; + TStMethod1Param = + function(Value1 : TStFloat) : TStFloat + of object; + TStMethod2Param = + function(Value1, Value2 : TStFloat) : TStFloat + of object; + TStMethod3Param = + function(Value1, Value2, Value3 : TStFloat) : TStFloat + of object; + +Add predefined constant values by using the AddConstant method: + + AddConstant('X', 50) + +Then, in any expression that uses the identifier "X", the value 50 will be +used when the expression is evaluated. + +Add references to variables in your program by using the AddVariable method: + + var + MyVar : TStFloat; + + AddVariable('MyVar', @MyVar); + +Whenever an expression is evaluated that contains the "MyVar" identifier, +the actual value of the variable (in your program) is retrieved and used +to compute the expression result. Changes to variable's value in your +program will be reflected when the expression is next evaluated. + +Two things to note: First, the variable must be a TStFloat type and second, +the variable must remain in "scope". In general, this means that the variable +must either be defined globally or as a class variable. You normally would not +use AddVariable for variables defined local to a procedure or function (a +stack variable). + +TStExpression offers a way to dynamically determine the value of an variable +or function that is being used in an expression -- the OnGetIdentValue event. +This event is fired if the expression parser is unable to locate the identifier +in its internal list of identifier names. In response to the event, you should +assign a value to the Value parameter that corresponds to the identifier name +passed to the event as the Identifier parameter. If no event handler is +assigned to this even and the expression parser is unable to locate a match for +an identifier used in an expression, an exception is raised. + + +Reference Section +----------------- + +methods +------- + +function AnalyzeExpression : TStFloat; +-> AnalyzeExpression causes the expression contained in the Expression property + to be evaluated and returns the resulting value as the function result. + + +procedure AddConstant(const Name : string; Value : TStFloat); +-> AddConstant adds named constant values for use within expressions. + +Example: AddConstant('X', 50) + + +procedure AddFunction0Param(const Name : string; FunctionAddr : TStFunction0Param); +procedure AddFunction1Param(const Name : string; FunctionAddr : TStFunction1Param); +procedure AddFunction2Param(const Name : string; FunctionAddr : TStFunction2Param); +procedure AddFunction3Param(const Name : string; FunctionAddr : TStFunction3Param); +-> AddFunctionXParam adds support for user-defined functions within expressions. + +The four variations allow defining functions with no parameters, or, with one, +two, or three parameters. Name is the identifier that is entered into the +expression. The name does not need to be the same as the actual function name. + +Parameter and function results must be defined as TStFloat. + + +procedure AddInternalFunctions; +-> AddInternalFunctions adds support for all of the predefined internal + functions. + +Since AddInternalFunctions is called by default, calling this routine without +first calling ClearIdentifiers will result in duplicate identifier exceptions. + + +procedure AddMethod0Param(const Name : string; MethodAddr : TStMethod0Param); +procedure AddMethod1Param(const Name : string; MethodAddr : TStMethod1Param); +procedure AddMethod2Param(const Name : string; MethodAddr : TStMethod2Param); +procedure AddMethod3Param(const Name : string; MethodAddr : TStMethod3Param); +-> AddMethodXParam adds support for user-defined methods within expressions. + +The four variations allow defining methods with no parameters, or, with one, +two, or three parameters. Name is the identifier that is entered into the +expression. The name does not need to be the same as the actual method name. + +Parameter and function results must be defined as TStFloat. + + +procedure AddVariable(const Name : string; VariableAddr : PStFloat); +-> Adds Name as a reference to a variable in your program. + +Name is the identifier used in expressions. + +Example: + + var + X : TStFloat; + ... + AddVariable('X', @X) + + +procedure ClearIdentifiers; +-> ClearIdentifiers removes all function, method, constant, and variable identifiers. + + +procedure GetIdentList(S : TStrings); +-> GetIdentList fills S with a list of identifiers current recognized. + + +procedure RemoveIdentifier(const Name : string); +-> RemoveIdentifier removes support for the identifier Name. + +If Name is not found, no action is taken. + + +properties +---------- +property AsFloat : TStFloat (run-time read-only) +-> AsFloat evaluates the expression and returns the value as a TStFloat + value; + +property AsInteger : Integer (run-time read-only) +-> AsInteger evaluates the expression and returns the value as a whole number + using the Round() function to convert the TStFloat value. + +property AsString : string (run-time read-only) +-> AsString evaluates the expression and returns the value as a string using + the FloatToStr() function to format the TStFloat value. + +property LastError : Integer (run-time read-only) +-> LastError returns the error code (zero if no error). + +property ErrorPosition : Integer (run-time read-only) +-> ErrorPosition returns the position of the error within the expression. + +ErrorPosition is valid only if LastError is non-zero. + +property Expression : string (run-time) +-> Expression defines the expression that should be evaluated. + +property AllowEqual : Boolean +default: True +-> AllowEqual determines if the use of the "=" symbol in the expression will + add constant declarations. + +If true, expressions like X = 5 will cause the identifer "X" to be added and +associated with the value 5. This expression will also return a value of 5 +when analyzed. If false, a bad character exception is raised. + + +events +------ +property OnAddIdentifier : TNotifyEvent +-> OnAddIdentifier defines an event that is fired when a new identifier + is added. + +This event is fired for additions of function, method, constant, and variable +identifiers. + +property OnGetIdentValue : TGetIdentValueEvent +TGetIdentValueEvent = + procedure(Sender : TObject; const Identifier : string; var Value : TStFloat) + of object; +-> OnGetIdentValue defines an event handler that is fired to obtain the value +for an identifier that was not found in the internal list of known identifiers. + + +TStExpressionEdit +================= +The TStExpressionEdit component is a simple descendant of a TEdit component +that adds one new method, two properties, and two new events. In all other +respects, this control is the same as the standard VCL TEdit control. + +The TStExpressionEdit uses an instance of the TStExpression component to do +most of the work. Any expression that is valid for the TStExpression +component can be entered into the component or assigned to the Text property. +The expression is evaluated when the component loses the focus (with AutoEval +true) or when the Evaluate method is called. Also, if AutoEval is true and +the control loses the focus, the resulting value is displayed in the control. + + +New properties and methods: + +function Evaluate : TStFloat; + +-> Evaluate evaluates the contents of the Text property as an expression +using the contained TStExpression component and returns the result of the +expression as the function result. + +If an error occurs an exception is raised unless an event handler for the +OnError event is assigned. In which case, the event is fired instead. + +Note: The AnalyzeExpr function (which is documented in the printed +manual and on-line help) is obsolete and is provided for backward +compatibility only. + + +property AutoEval : Boolean + +-> AutoEval determines if the entered expression is automatically evaluated + when the control loses the focus. + +If AutoEval is true, the Evaluate method is called automatically and the +Text of the edit control is set to the result of evaluating the expression. +If False, no additional action is taken. + + +property Expr : TStExpression (run-time) + +-> Expr provides access to the contained TStExpression component and all of + its properties, methods, and events. + + +property OnAddIdentifier : TNotifyEvent + +-> OnAddIdentifier defines an event that is fired when an identifier is + added to the internal TStExpression component. + +This event is fired to notify you that a constant or function identifier has +been added to the contained TStExpression component. + + +property OnError : TStExprErrorEvent + + TStExprErrorEvent = + procedure(Sender : TObject; ErrorNumber : LongInt; const ErrorStr : string) + of object; + +-> OnError defines an event that is fired when an evaluation error occurs. diff --git a/components/systools/source/run/stfin.pas b/components/systools/source/run/stfin.pas new file mode 100644 index 000000000..0fbafdf5b --- /dev/null +++ b/components/systools/source/run/stfin.pas @@ -0,0 +1,1312 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StFIN.pas 4.04 *} +{*********************************************************} +{* SysTools: Financial math functions modeled on *} +{* those in Excel *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit StFIN; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + {$IFDEF UseMathUnit} + Math, + {$ELSE} + StMath, + {$ENDIF} + SysUtils, + StBase, + StConst, + StDate; + +type + TStPaymentTime = (ptEndOfPeriod, ptStartOfPeriod); + TStFrequency = (fqAnnual, fqSemiAnnual, fqQuarterly, fqMonthly); + TStBasis = (BasisNASD, {US (NASD) 30/360} + BasisActAct, {Actual/actual} + BasisAct360, {Actual/360} + BasisAct365, {Actual/365} + BasisEur30360); {European 30/360} + + TStDateArray = array[0..(StMaxBlockSize div SizeOf(TStDate))-1] of TStDate; + + +const + StDelta : Extended = 0.00001; {delta for difference equations} + StEpsilon : Extended = 0.00001; {epsilon for difference equations} + StMaxIterations : Integer = 100; {max attempts for convergence} + + +function AccruedInterestMaturity(Issue, Maturity : TStDate; + Rate, Par : Extended; + Basis : TStBasis) : Extended; + {-Returns the accrued interest for a security that pays interest at maturity} + +function AccruedInterestPeriodic(Issue, Settlement, Maturity : TStDate; + Rate, Par : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; + {-Returns the accrued interest for a security that pays periodic interest} + +function BondDuration(Settlement, Maturity : TStDate; + Rate, Yield : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; + {-Returns the Macauley duration for an assumed par value of $100} + +function BondPrice(Settlement, Maturity : TStDate; + Rate, Yield, Redemption : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; + {-Returns the "clean" bond price per $100 face value of a security} + +function CumulativeInterest(Rate : Extended; + NPeriods : Integer; + PV : Extended; + StartPeriod, EndPeriod : Integer; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; + {-Returns the cumulative interest paid on a loan in specified periods} + +function CumulativePrincipal(Rate : Extended; + NPeriods : Integer; + PV : Extended; + StartPeriod, EndPeriod : Integer; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; + {-Returns the cumulative principal paid on a loan in specified periods} + +function DayCount(Day1, Day2 : TStDate; Basis : TStBasis) : LongInt; + {-Returns the number of days from Day1 to Day2 according to day count basis} + +function DecliningBalance(Cost, Salvage : Extended; + Life, Period, Month : Integer) : Extended; + {-Fixed rate declining balance depreciation} + +function DiscountRate(Settlement, Maturity : TStDate; + Price, Redemption : Extended; + Basis : TStBasis) : Extended; + {-Returns the discount Rate for a security} + +function DollarToDecimal(FracDollar : Extended; + Fraction : Integer) : Extended; + {-Converts a fractional dollar value to decimal dollar value} + +function DollarToDecimalText(DecDollar : Extended) : string; + {-Converts a decimal dollar value into an English text string} + +function DollarToFraction(DecDollar : Extended; + Fraction : Integer) : Extended; + {-Converts a decimal dollar value to fractional dollar value} + +function DollarToFractionStr(FracDollar : Extended; + Fraction : Integer) : string; + {-Converts a fractional dollar value to number string} + +function EffectiveInterestRate(NominalRate : Extended; + Frequency : TStFrequency) : Extended; + {-Converts nominal annual interest Rate to effective Rate} + +function FutureValue(Rate : Extended; + NPeriods : Integer; + Pmt, PV : Extended; + Frequency : TStFrequency; + Timing: TStPaymentTime) : Extended; + {-Returns the future value of an annuity} + + function FutureValueSchedule(Principal : Extended; + const Schedule : array of Double) : Extended; + +function FutureValueSchedule16(Principal : Extended; + const Schedule; NRates : Integer) : Extended; + {-Returns the future value of investment with variable interest rates} + +function InterestRate(NPeriods : Integer; + Pmt, PV, FV : Extended; + Frequency : TStFrequency; + Timing : TStPaymentTime; + Guess : Extended) : Extended; + {-Returns the interest Rate per period of an annuity} + + function InternalRateOfReturn(const Values : array of Double; + Guess : Extended) : Extended; + +function InternalRateOfReturn16(const Values; NValues : Integer; + Guess : Extended) : Extended; + {-Returns internal rate of return of a series of periodic cash flows} + +function IsCardValid(const S : string) : Boolean; + {-Checks for valid credit card number (MasterCard, Visa, AMEX, Discover)} + +function ModifiedDuration(Settlement, Maturity : TStDate; + Rate, Yield : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; + {-Returns the modified duration for bond with an assumed par value of $100} + + function ModifiedIRR(const Values : array of Double; + FinanceRate, ReinvestRate : Extended) : Extended; + +function ModifiedIRR16(const Values; NValues : Integer; + FinanceRate, ReinvestRate : Extended) : Extended; + {-Returns the MIRR for a series of periodic cash flows} + + function NetPresentValue(Rate : Extended; + const Values : array of Double) : Extended; + +function NetPresentValue16(Rate : Extended; + const Values; NValues : Integer) : Extended; + {-Returns the net present value of a series of periodic cash flows} + +function NominalInterestRate(EffectRate : Extended; + Frequency : TStFrequency) : Extended; + {-Converts effective annual interest Rate to nominal Rate} + + function NonperiodicIRR(const Values : array of Double; + const Dates : array of TStDate; + Guess : Extended) : Extended; + +function NonperiodicIRR16(const Values; + const Dates; NValues : Integer; + Guess : Extended) : Extended; + {-Returns the IRR for a series of irregular cash flows} + + function NonperiodicNPV(Rate : Extended; + const Values : array of Double; + const Dates : array of TStDate) : Extended; + +function NonperiodicNPV16(Rate : Extended; + const Values; + const Dates; + NValues : Integer) : Extended; + {-Returns the net present value for a series of irregular cash flows} + +function Payment(Rate : Extended; + NPeriods : Integer; + PV, FV : Extended; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; + {-Returns the interest payment per period in an annuity} + +function Periods(Rate : Extended; + Pmt, PV, FV : Extended; + Frequency : TStFrequency; + Timing: TStPaymentTime) : Integer; + {-Returns the number of periods for an annuity} + +function PresentValue(Rate : Extended; + NPeriods : Integer; + Pmt, FV : Extended; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; + {-Returns present value of an annity} + +function ReceivedAtMaturity(Settlement, Maturity : TStDate; + Investment, Discount : Extended; + Basis : TStBasis) : Extended; + {-Returns the amount received at Maturity for a fully invested security} + +function RoundToDecimal(Value : Extended; + Places : Integer; + Bankers : Boolean) : Extended; + {-Rounds a real value to the specified number of decimal places} + +function TBillEquivYield(Settlement, Maturity : TStDate; + Discount : Extended) : Extended; + {-Returns the bond-equivalent yield for a treasury bill} + +function TBillPrice(Settlement, Maturity : TStDate; + Discount : Extended) : Extended; + {-Returns the price per $100 face value for a treasury bill} + +function TBillYield(Settlement, Maturity : TStDate; + Price : Extended) : Extended; + {-Returns the yield for a treasury bill} + +function VariableDecliningBalance(Cost, Salvage : Extended; + Life : Integer; + StartPeriod, EndPeriod, Factor : Extended; + NoSwitch : boolean) : Extended; + {-Variable rate declining balance depreciation} + +function YieldDiscounted(Settlement, Maturity : TStDate; + Price, Redemption : Extended; + Basis : TStBasis) : Extended; + {-Returns the annual yield for a discounted security} + +function YieldPeriodic(Settlement, Maturity : TStDate; + Rate, Price, Redemption : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; + {-Returns the yield on a security that pays periodicinterest} + +function YieldMaturity(Issue, Settlement, Maturity : TStDate; + Rate, Price : Extended; + Basis : TStBasis) : Extended; + {-Returns the annual yield of a security that pays interest at Maturity} + + +{========================================================================} + +implementation + +const + PaymentType : array[TStPaymentTime] of Integer = (0, 1); + {Used for converting Timing to integer 0 or 1} + + CouponsPerYear : array[TStFrequency] of Integer = (1, 2, 4, 12); + {Used for converting Frequency to integer 1, 2, 4, or 12} + + CouponPeriod : array[TStFrequency] of Integer = (12, 6, 3, 1); + {Used for converting Frequency to duration} + + DefaultGuess : Extended = 0.1; + {Starting point for rate approximation routines} + +var + RecipLn10 : Extended; + {Used for common log computation} + + +{================= Local routines used by this unit ==================} + +procedure RaiseStFinError(Code : Longint); +begin + Raise EStFinError.CreateResTP(Code, 0); +end; + +{-------------------------------------------------------} + +function Exp10(Exponent : Extended) : Extended; + {-Returns 10^Exponent} +begin + Result := Power(10.0, Exponent); +end; + +{-------------------------------------------------------} + +function Log10(Value : Extended) : Extended; + {-Returns common log of Value} +begin + Result := Ln(Value) * RecipLn10; +end; + +{-------------------------------------------------------} + +function DayCount(Day1, Day2 : TStDate; Basis : TStBasis) : LongInt; + {-The number of days from Day1 to Day2 according to day count basis} +var + BDT : TStBondDateType; +begin + case Basis of + BasisNASD : BDT := bdt30360PSA; + BasisEur30360 : BDT := bdt30E360; + else + BDT := bdtActual; + end; + Result := Longint(BondDateDiff(Day1, Day2, BDT)); +end; + +{-------------------------------------------------------} + +function LastCoupon(Settlement, Maturity : TStDate; + Frequency : TStFrequency) : TStDate; + {-The last coupon date prior to settlement} +var + Last : TStDate; + Months : Integer; +begin + Last := Maturity; + Months := 0; + while (Last >= Settlement) do begin + Months := Months + CouponPeriod[Frequency]; + Last := IncDateTrunc(Maturity, -Months, 0); + end; + Result := Last; +end; + +{-------------------------------------------------------} + +function NextCoupon(Settlement, Maturity : TStDate; + Frequency : TStFrequency) : TStDate; + {-The next coupon date after settlement} +var + Next : TStDate; +begin + Next := LastCoupon(Settlement, Maturity, Frequency); + Result := IncDateTrunc(Next, CouponPeriod[Frequency], 0); +end; + +{-------------------------------------------------------} + +function CouponsToMaturity(Settlement, Maturity : TStDate; + Frequency : TStFrequency) : Integer; + {-The number of coupons remaining after settlement} +var + CouponDate : TStDate; + Months : Integer; + Coupons : Integer; +begin + CouponDate := Maturity; + Coupons := 0; + Months := 0; + while (CouponDate > Settlement) do begin + Months := Months + CouponPeriod[Frequency]; + CouponDate := IncDateTrunc(Maturity, -Months, 0); + Coupons := Coupons + 1; + end; + Result := Coupons; +end; + +{-------------------------------------------------------} + +function DayCountFraction(Day1, Day2, Settlement, Maturity : TStDate; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; + {-The number of days from Day1 to Day2 divided by days/year + except for Act/Act which uses actual coupon period x frequency} +var + Last, Next : TStDate; + DPY : Integer; +begin + if (Basis = BasisActAct) then begin + Last := LastCoupon(Settlement, Maturity, Frequency); + Next := NextCoupon(Settlement, Maturity, Frequency); + DPY := DayCount(Last, Next, Basis) * CouponsPerYear[Frequency]; + end else if (Basis = BasisAct365) then + DPY := 365 + else + DPY := 360; + Result := DayCount(Day1, Day2, Basis) / DPY; +end; + +{-------------------------------------------------------} + +function BondDirtyPrice(Settlement, Maturity : TStDate; + Rate, Yield, Redemption : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; + {-Bond Price including interest accrued in current coupon period} +var + C, DCF, Yw : Extended; + Vn, Vdcf : Extended; + Next : TStDate; + N, W : Integer; +begin + W := CouponsPerYear[Frequency]; + C := Redemption * (Rate / W); + Yw := Yield / W; + N := CouponsToMaturity(Settlement, Maturity, Frequency); + Next := NextCoupon(Settlement, Maturity, Frequency); + DCF := DayCountFraction(Settlement, Next, Settlement, Maturity, + Frequency, Basis); + Vdcf := Power(1.0 / (1.0 + Yw), DCF * W); + Vn := Power(1.0 / (1.0 + Yw), N - 1.0); + Result := Vdcf * (( C * (1.0 - Vn) / Yw) + Redemption * Vn + C); +end; + + + +{====================== Public Routines ============================} + + +function AccruedInterestMaturity(Issue, Maturity : TStDate; + Rate, Par : Extended; + Basis : TStBasis) : Extended; +var + DCF : Extended; +begin + If (Rate <= 0.0) or (Par <= 0.0) or (Issue >= Maturity) then + RaiseStFinError(stscFinBadArg); + DCF := DayCountFraction(Issue, Maturity, Issue, Maturity, + fqAnnual, Basis); + Result := Par * Rate * DCF; +end; + +{-------------------------------------------------------} + +function AccruedInterestPeriodic(Issue, Settlement, Maturity : TStDate; + Rate, Par : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; +var + Last : TStDate; + DCF : Extended; +begin + if (Rate <= 0.0) or (Par <= 0.0) or (Issue >= Settlement) then + RaiseStFinError(stscFinBadArg); + Last := LastCoupon(Settlement, Maturity, Frequency); + if (Issue > Last) then + Last := Issue; + DCF := DayCountFraction(Last, Settlement, Settlement, Maturity, + Frequency, Basis); + Result := Par * Rate * DCF; +end; + +{-------------------------------------------------------} + +function BondDuration(Settlement,Maturity : TStDate; + Rate, Yield : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; +var + B, dB : Extended; + Yw : Extended; +begin + if (Rate < 0.0) or (Yield < 0.0) or (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + Yw := Yield / CouponsPerYear[Frequency]; + B := BondDirtyPrice(Settlement, Maturity, Rate, Yield, 100.0, + Frequency, Basis); + if (B <> 0.0) then begin + dB := BondDirtyPrice(Settlement, Maturity, Rate, Yield + StDelta, 100.0, + Frequency, Basis) - B; + Result := -((1.0 + Yw) / B) * (dB / StDelta); + end else + Result := 0; +end; + +{-------------------------------------------------------} + +function BondPrice(Settlement, Maturity : TStDate; + Rate, Yield, Redemption : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; +var + B, DCF : Extended; + Last : TStDate; +begin + if (Yield < 0.0) or (Rate < 0.0) or (Redemption <= 0) or + (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + B := BondDirtyPrice(Settlement, Maturity, Rate, Yield, Redemption, + Frequency, Basis); + Last := LastCoupon(Settlement, Maturity, Frequency); + DCF := DayCountFraction(Last, Settlement, Settlement, Maturity, + Frequency, Basis); + Result := B - Redemption * Rate * DCF; +end; + +{-------------------------------------------------------} + +function CumulativeInterest(Rate : Extended; + NPeriods : Integer; + PV : Extended; + StartPeriod, EndPeriod : Integer; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; +var + P, CP : Extended; +begin + if (Rate <=0.0) or (NPeriods <= 0) or (PV <= 0.0) or (StartPeriod < 1) or + (EndPeriod < 1) or (StartPeriod > EndPeriod) then + RaiseStFinError(stscFinBadArg); + P := Payment(Rate, NPeriods, PV, 0.0, Frequency, Timing); + CP := CumulativePrincipal(Rate, NPeriods, PV, StartPeriod, EndPeriod, + Frequency, Timing); + Result := P * (EndPeriod - (StartPeriod - 1.0)) - CP; +end; + +{-------------------------------------------------------} + +function CumulativePrincipal(Rate : Extended; + NPeriods : Integer; + PV : Extended; + StartPeriod, EndPeriod : Integer; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; +var + P : Extended; +begin + if (Rate <=0.0) or (NPeriods <= 0) or (PV <= 0.0) or (StartPeriod < 1) or + (EndPeriod < 1) or (StartPeriod > EndPeriod) then + RaiseStFinError(stscFinBadArg); + P := Payment(Rate, NPeriods, PV, 0.0, Frequency, Timing); + Result := FutureValue(Rate, StartPeriod - 1, P, PV, Frequency, Timing) - + FutureValue(Rate, EndPeriod, P, PV, Frequency, Timing); +end; + +{-------------------------------------------------------} + +function DecliningBalance(Cost, Salvage : Extended; + Life, Period, Month : Integer) : Extended; +var + Rate : Extended; + DPv : Extended; + TDPv : Extended; + I : Integer; +begin + if (Cost <= 0.0) or (Cost < Salvage) or (Period < 1) or (Life < 2) or + (Period > (Life + 1)) then + RaiseStFinError(stscFinBadArg); + DPv := 0.0; + TDPv := 0.0; + if (Salvage = 0) then + Salvage := 0.001; + if (Month = 0) then + Month := 12; + Rate := RoundToDecimal(1.0 - Power(Salvage / Cost, 1.0 / Life), 3, false); + for I := 1 to Period do begin + if (I = 1) then + DPv := (Cost * Rate * Month) / 12.0 {1st Period} + else if (I = (Life + 1)) then + DPv := (Cost - TDPv) * Rate * (12.0 - Month) / 12.0 {Last Period} + else + DPv := (Cost - TDPv) * Rate; {All the rest} + TDpv := TDpv + Dpv + end; + Result := RoundToDecimal(Dpv, 3, False); +end; + +{-------------------------------------------------------} + +function DiscountRate(Settlement, Maturity : TStDate; + Price, Redemption : Extended; + Basis : TStBasis) : Extended; +var + DCF : Extended; +begin + If (Price <= 0.0) or (Redemption <= 0.0) or (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity, + fqAnnual, Basis); + Result := (Redemption - Price) / (Redemption * DCF); +end; + + {-------------------------------------------------------} + +function DollarToDecimal(FracDollar : Extended; + Fraction : Integer) : Extended; +var + I, F, N : Extended; +begin + if (Fraction < 1) then + RaiseStFinError(stscFinBadArg); + I := Int(FracDollar); {Integral part} + N := Int(Log10(Fraction) + 1.0); {Number of decimal places} + F := Frac(FracDollar); {Fractional part} + Result := I + (F * Exp10(N) / Fraction); +end; + +{-------------------------------------------------------} + +function DollarToDecimalText(DecDollar : Extended) : string; +var + A, P : Extended; + N, I : Integer; + Str : string; + T : Longint; + CentVal : Integer; +const + Orders : array[0..5] of string = ('', 'Thousand ', 'Million ', + 'Billion ', 'Trillion ', 'Quadrillion '); + + function Text100(Num: Longint) : string; + {formats an integer in the range 0 to 999} + var + I, J : Integer; + A, T : Longint; + S : string; + const + Tens : array[0..9] of string = + ('', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', + 'Sixty', 'Seventy', 'Eighty', 'Ninety'); + Ones : array[0..19] of string = + ('', 'One', 'Two', 'Three', 'Four', 'Five', + 'Six', 'Seven', 'Eight', 'Nine', 'Ten', + 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', + 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'); + begin + S := ''; + I := 0; + J := 0; + Result := S; + if (Num = 0) then + Exit; + A := Num; + T := A div 100; + if (T > 0) then begin + I := T; {I = Hundreds digit} + A := A - (T * 100); + end; + T := A div 10; + if (T > 1) then begin + J := T; {J = Tens digit} + A := A - (T * 10); {A = Ones digit} + end; + if (I > 0) then + S := Ones[I] + ' Hundred'; + if (J > 0) then begin + if (I > 0) then + S := S + ' ' + Tens[J] + else + S := S + Tens[J]; + end; + if (A > 0) then begin + if (J > 0) then + S := S + '-'; + if (I > 0) and (J = 0) then + S := S + ' ' + Ones[A] + else + S := S + Ones[A]; + end; + Result := S; + end; + +begin + Str := ''; + if (DecDollar < 0) then + RaiseStFinError(stscFinBadArg); + if (DecDollar > 0) then begin + N := Trunc(Log10(DecDollar)); + if (N > 17) then {DecDollar too large} + RaiseStFinError(stscFinBadArg); + A := DecDollar; + for I := N downto 0 do begin + P := Int(Exp10(I * 3)); + T := Trunc(A / P); + if (T > 0) then + Str := Str + {' ' +} Text100(T) + ' ' + Orders[I]; + A := A - (T * P); + end; + end; + if (Str = '') then + Str := 'Zero '; + Str := Str + 'and '; + CentVal := Round(Frac(DecDollar) * 100); + if (CentVal < 10) then + Str := Str + '0'; + Result := Str + IntToStr(CentVal) + '/100'; +end; + +{-------------------------------------------------------} + +function DollarToFraction(DecDollar : Extended; + Fraction : Integer) : Extended; +var + I, F, N : Extended; +begin + if (Fraction < 1) then + RaiseStFinError(stscFinBadArg); + I := Int(DecDollar); {Integral part} + N := Int(Log10(Fraction) + 1.0); {Number of decimal places} + F := Frac(DecDollar); {Fractional part} + Result := I + (F * Fraction / Exp10(N)); +end; + +{-------------------------------------------------------} + +function DollarToFractionStr(FracDollar : Extended; + Fraction : Integer) : string; +var + I, F, N : Extended; +begin + Result := ''; + if (Fraction < 1) then + RaiseStFinError(stscFinBadArg); + I := Int(FracDollar); {Integral part} + N := Int(Log10(Fraction) + 1.0); {Number of decimal places} + F := Frac(FracDollar) * Exp10(N); {Fractional part} + Result := IntToStr(Trunc(I)); + if (F > 0) then + Result := Result + ' ' + FloatToStrF(F, ffNumber, Trunc(N), 0) + + '/' + IntToStr(Fraction); +end; + +{-------------------------------------------------------} + +function EffectiveInterestRate(NominalRate : Extended; + Frequency : TStFrequency) : Extended; +var + W : Integer; +begin + if (NominalRate <= 0.0) then + RaiseStFinError(stscFinBadArg); + W := CouponsPerYear[Frequency]; + Result := Power(1.0 + NominalRate / W, W) - 1.0; +end; + +{-------------------------------------------------------} + +function FutureValue(Rate : Extended; + NPeriods : Integer; + Pmt, PV : Extended; + Frequency : TStFrequency; + Timing: TStPaymentTime) : Extended; +var + S, Rw : Extended; + PT : Integer; + +begin + PT := PaymentType[Timing]; + Rw := Rate / CouponsPerYear[Frequency]; + S := Power(1.0 + Rw, NPeriods); + Result := -((PV * S) + Pmt * (S - 1.0) * (1.0 + Rw * PT) / Rw); +end; + +{-------------------------------------------------------} + + function FutureValueSchedule(Principal : Extended; + const Schedule : array of Double) : Extended; + begin + Result := FutureValueSchedule16(Principal, Schedule, + High(Schedule) + 1); + end; + +function FutureValueSchedule16(Principal : Extended; + const Schedule; NRates : Integer) : Extended; +var + I : Integer; +begin + Result := Principal; + for I := 0 to (NRates - 1) do + Result := Result * (1.0 + TDoubleArray(Schedule)[I]); +end; + +{-------------------------------------------------------} + +function InterestRate(NPeriods : Integer; + Pmt, PV, FV : Extended; + Frequency : TStFrequency; + Timing : TStPaymentTime; + Guess : Extended) : Extended; +var + Rate : Extended; + NextRate : Extended; + T, dT : Extended; + Count : Integer; +begin + Count := 0; + NextRate := Guess; + if (Guess = 0.0) then + NextRate := DefaultGuess; + {Solve FV(rate) = FV for rate by Newton's method} + repeat + Rate := NextRate; + if (Rate <= - CouponsPerYear[Frequency]) then + Rate := -0.999 * CouponsPerYear[Frequency]; + T := FutureValue(Rate, NPeriods, Pmt, PV, Frequency, Timing) - FV; + dT := FutureValue(Rate + StDelta, NPeriods, Pmt, PV, Frequency, + Timing) - FV - T; + if (dT = 0.0) then + Count := StMaxIterations + else + NextRate := Rate - StDelta * T / dT; + Inc(Count); + until (Abs(NextRate - Rate) < StEpsilon) or (Count > StMaxIterations); + if (Count > StMaxIterations) then + RaiseStFinError(stscFinNoConverge); + Result := NextRate; +end; + +{-------------------------------------------------------} + + function InternalRateOfReturn(const Values : array of Double; + Guess : Extended) : Extended; + begin + Result := InternalRateOfReturn16(Values, High(Values) + 1, Guess); + end; + +function InternalRateOfReturn16(const Values; + NValues : Integer; + Guess : Extended) : Extended; +var + Rate : Extended; + NextRate : Extended; + PV : Extended; + dPV : Extended; + Count : Integer; +begin + Count := 0; + NextRate := Guess; + if (Guess = 0.0) then + NextRate := DefaultGuess; + {Solve NPV(Rate) = 0 for rate by Newton's method} + repeat + Rate := NextRate; + if (Rate <= -1.0) then + Rate := -0.999; + PV := NetPresentValue16(Rate, Values, NValues); + dPV := NetPresentValue16(Rate + StDelta, Values, NValues) - PV; + if (dPV = 0.0) then + Count := StMaxIterations + else + NextRate := Rate - (StDelta * PV) / dPV; + Inc(Count); + until (Abs(NextRate - Rate) < StEpsilon) or (Count > StMaxIterations); + if (Count > StMaxIterations) then + RaiseStFinError(stscFinNoConverge); + Result := NextRate; +end; + +{-------------------------------------------------------} + +function IsCardValid(const S : string) : Boolean; +const + Ord0 = Ord('0'); +var + Temp : string; + I, J, K : Integer; +begin + Result := False; + Temp := ''; + for I := 1 to Length(S) do + if (S[I] in ['0'..'9']) then + Temp := Temp + S[I]; + if Temp = '' then + Exit; + K := 0; + I := 1; + if not Odd(Length(Temp)) then begin + J := Ord(Temp[I]) - Ord0; + J := J shl 1; + if J > 9 then + J := J - 9; + K := K + J; + Inc(I); + end; + while I <= Length(Temp) do begin + K := K + Ord(Temp[I]) - Ord0; + Inc(I); + if I > Length(Temp) then + Break; + J := Ord(Temp[I]) - Ord0; + J := J shl 1; + if J > 9 then + J := J - 9; + K := K + J; + Inc(I); + end; + Result := (K mod 10 = 0); +end; + +{-------------------------------------------------------} + +function ModifiedDuration(Settlement, Maturity : TStDate; + Rate, Yield : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; +begin + if (Rate < 0.0) or (Yield < 0.0) or (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + Result := BondDuration(Settlement, Maturity, Rate, Yield, + Frequency, Basis)/ (1.0 + Yield / CouponsPerYear[Frequency]); +end; + +{-------------------------------------------------------} + + function ModifiedIRR(const Values : array of Double; + FinanceRate, ReinvestRate : Extended) : Extended; + begin + Result := ModifiedIRR16(Values, High(Values) + 1, FinanceRate, + ReinvestRate); + end; + +function ModifiedIRR16(const Values; + NValues : Integer; + FinanceRate, ReinvestRate : Extended) : Extended; +var + NPVPos : Extended; + NPVNeg : Extended; + Val : Extended; + Rn, Fn : Extended; + I : Integer; +begin + NPVPos := 0.0; + NPVNeg := 0.0; + for I := 0 to (NValues - 1) do begin + Val := TDoubleArray(Values)[I]; + if (Val > 0.0) then + NPVPos := NPVPos + Val / Power(1.0 + ReinvestRate, I + 1.0) + else + NPVNeg := NPVNeg + Val / Power(1.0 + FinanceRate, I + 1.0); + end; + Rn := Power(1.0 + ReInvestRate, NValues); + Fn := 1.0 + FinanceRate; + Result := Power(-NPVPos * Rn / (NPVNeg * Fn), 1.0 / (NValues - 1.0)) - 1.0; +end; + +{-------------------------------------------------------} + + function NetPresentValue(Rate : Extended; + const Values : array of Double) : Extended; + begin + Result := NetPresentValue16(Rate, Values, High(Values) + 1); + end; + +function NetPresentValue16(Rate : Extended; + const Values; + NValues : Integer) : Extended; +var + I : Integer; +begin + Result := 0; + for I := 0 to (NValues - 1) do + Result := Result + TDoubleArray(Values)[I] / Power(1.0 + Rate, I + 1.0); +end; + +{-------------------------------------------------------} + +function NominalInterestRate(EffectRate : Extended; + Frequency : TStFrequency) : Extended; +var + W : Extended; +begin + if (EffectRate <= 0.0) then + RaiseStFinError(stscFinBadArg); + W := CouponsPerYear[Frequency]; + Result := W * (Power(EffectRate + 1.0, 1.0 / W) - 1.0); +end; + +{-------------------------------------------------------} + + function NonperiodicIRR(const Values : array of Double; + const Dates : array of TStDate; + Guess : Extended) : Extended; + begin + Result := NonPeriodicIRR16(Values, Dates, High(Values) + 1, Guess); + end; + +function NonperiodicIRR16(const Values; + const Dates; + NValues : Integer; + Guess : Extended) : Extended; +var + Rate : Extended; + NextRate : Extended; + PV, dPV : Extended; + Count : Integer; +begin + Count := 0; + NextRate := Guess; + if (Guess = 0.0) then + NextRate := DefaultGuess; + {Solve XNPV(Rate) = 0 for rate by Newton's method} + repeat + Rate := NextRate; + if (Rate <= -1.0) then + Rate := -0.999; + PV := NonPeriodicNPV16(Rate, Values, Dates, NValues); + dPV := NonPeriodicNPV16(Rate + StDelta, Values, Dates, NValues) - PV; + if (dPV = 0.0) then + Count := StMaxIterations + else + NextRate := Rate - (StDelta * PV) / dPV; + Inc(Count); + until (Abs(NextRate - Rate) < StEpsilon) or (Count > StMaxIterations); + if (Count > StMaxIterations) then + RaiseStFinError(stscFinNoConverge); + Result := NextRate; +end; + +{-------------------------------------------------------} + + function NonperiodicNPV(Rate : Extended; + const Values : array of Double; + const Dates : array of TStDate) : Extended; + begin + Result := NonperiodicNPV16(Rate, Values, Dates, High(Values) + 1); + end; + +function NonperiodicNPV16(Rate : Extended; + const Values; + const Dates; + NValues : Integer) : Extended; +var + Day1 : TStDate; + Diff : Double; + I : Integer; +begin + Result := 0.0; + Day1 := TStDateArray(Dates)[0]; + for I := 0 to (NValues - 1) do begin + Diff := TStDateArray(Dates)[I] - Day1; + if (Diff < 0) then + RaiseStFinError(stscFinBadArg); + Result := Result + TDoubleArray(Values)[I] / Power(1.0 + Rate, Diff / 365.0); + end; +end; + +{-------------------------------------------------------} + +function Payment(Rate : Extended; + NPeriods : Integer; + PV, FV : Extended; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; +var + PT, Rw, S : Extended; +begin + PT := PaymentType[Timing]; + Rw := Rate / CouponsPerYear[Frequency]; + S := Power(1.0 + Rw, NPeriods); + Result := Rw * (FV - PV * S) / ((S - 1.0) * (1.0 + Rw * PT)); +end; + +{-------------------------------------------------------} +function Periods(Rate : Extended; + Pmt, PV, FV : Extended; + Frequency : TStFrequency; + Timing: TStPaymentTime) : Integer; +var + S, Rw : Extended; + +begin + Rw := Rate / CouponsPerYear[Frequency]; + S := Pmt * (1.0 + Rw * PaymentType[Timing]); + Result := Round(Ln((Rw*FV + S) / (Rw*PV + S)) / Ln(1.0 + Rw)); +end; + +{-------------------------------------------------------} + +function PresentValue(Rate : Extended; + NPeriods : Integer; + Pmt, FV : Extended; + Frequency : TStFrequency; + Timing : TStPaymentTime) : Extended; +var + PT, Rw, S : Extended; +begin + PT := PaymentType[Timing]; + Rw := Rate / CouponsPerYear[Frequency]; + S := Power(1.0 + Rw, -NPeriods); + Result := (FV * S) + Pmt * (S - 1.0) * (1.0 + Rw * PT) / Rw; +end; + +{-------------------------------------------------------} + +function ReceivedAtMaturity(Settlement, Maturity : TStDate; + Investment, Discount : Extended; + Basis : TStBasis) : Extended; +var + DCF : Extended; +begin + if (Investment <= 0.0) or (Discount <= 0.0) or (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity, + fqAnnual, Basis); + Result := Investment / (1.0 - Discount * DCF); +end; + +{-------------------------------------------------------} + + {revised} +function RoundToDecimal(Value : Extended; + Places : Integer; + Bankers : Boolean) : Extended; +var + Val, IV, N, F : Extended; + T : Integer; +begin + IV := 0; + N := Exp10(Places); + if (Places > 0) then + IV := Int(Value); + Val := (Value - IV) * N; + T := Trunc(Val); + F := (Val - T); + if Bankers then + Val := Round(Val) / N {Delphi's Round does Bankers} + else begin + if Abs(Round(10.0 * F)) >= 5 then begin + if (F > 0) then + Val := (T + 1.0) / N + else + Val := (T - 1.0) / N; + end else + Val := T / N; + end; + Result := Val + IV; +end; + +{-------------------------------------------------------} + +function TBillEquivYield(Settlement, Maturity : TStDate; + Discount : Extended) : Extended; +var + DCF : Extended; +begin + if (Discount <= 0.0) or (Settlement > Maturity) then + RaiseStFinError(stscFinBadArg); + DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity, + fqAnnual, BasisAct360); + if (DCF > 1.0) then + RaiseStFinError(stscFinBadArg); + Result := (365.0 / 360.0) * Discount / (1.0 - Discount * DCF); +end; + +{-------------------------------------------------------} + +function TBillPrice(Settlement, Maturity : TStDate; + Discount : Extended) : Extended; +var + DCF : Extended; +begin + if (Discount <= 0.0) or (Settlement > Maturity) then + RaiseStFinError(stscFinBadArg); + DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity, + fqAnnual, BasisAct360); + if (DCF > 1.0) then + RaiseStFinError(stscFinBadArg); + Result := 100.0 * ( 1.0 - Discount * DCF); +end; + +{-------------------------------------------------------} + +function TBillYield(Settlement, Maturity : TStDate; + Price : Extended) : Extended; +var + DCF : Extended; +begin + if (Price <= 0.0) or (Settlement > Maturity) then + RaiseStFinError(stscFinBadArg); + DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity, + fqAnnual, BasisAct360); + if (DCF > 1.0) then + RaiseStFinError(stscFinBadArg); + Result := ((100.0 - Price) / Price) * (1.0 / DCF); +end; + +{-------------------------------------------------------} + +function VariableDecliningBalance(Cost, Salvage : Extended; + Life : Integer; + StartPeriod, EndPeriod, Factor : Extended; + NoSwitch : Boolean) : Extended; +var + VDB : Extended; + SLD : Extended; + Rate : Extended; +begin + if (Cost <= 0.0) or (Cost < Salvage) or (Life < 2) or (EndPeriod > Life) or + (StartPeriod > EndPeriod) or (StartPeriod < 0) then + RaiseStFinError(stscFinBadArg); + if (Factor = 0.0) then + Rate := 2.0 / Life + else + Rate := Factor / Life; + SLD := (Cost - Salvage) * (EndPeriod - StartPeriod) / Life; + VDB := Cost * (Power(1.0 - Rate, StartPeriod) - Power(1.0 - Rate, EndPeriod)); + if (not NoSwitch) and (SLD > VDB) then + Result := SLD + else + Result := VDB; +end; + +{-------------------------------------------------------} + +function YieldDiscounted(Settlement, Maturity : TStDate; + Price, Redemption : Extended; + Basis : TStBasis) : Extended; +var + DCF : Extended; +begin + if (Price <= 0.0) or (Redemption <= 0.0) or (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity, + fqAnnual, Basis); + Result := (Redemption - Price) / (Price * DCF); +end; + +{-------------------------------------------------------} + +function YieldPeriodic(Settlement, Maturity : TStDate; + Rate, Price, Redemption : Extended; + Frequency : TStFrequency; + Basis : TStBasis) : Extended; +var + Yield : Extended; + NextYield : Extended; + P, dP : Extended; + Count : Integer; +begin + if (Price <= 0.0) or (Rate < 0.0) or (Redemption <= 0.0) or + (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + Count := 0; + NextYield := Rate; + repeat {Solve B = BondPrice(yield) - Price = 0 by Newton's method} + if (NextYield > 0) then + Yield := NextYield + else + Yield := 0.001; + P := BondPrice(Settlement, Maturity, Rate, Yield, Redemption, + Frequency, Basis) - Price; + dP := BondPrice(Settlement, Maturity, Rate, Yield + StDelta, + Redemption, Frequency, Basis) - Price - P; + if (dP = 0.0) then + Count := StMaxIterations + else + NextYield := Yield - StDelta * P / dP; + Inc(Count); + until (Abs(NextYield - Yield) < StEpsilon) or (Count > StMaxIterations); + if (Count > StMaxIterations) then + RaiseStFinError(stscFinNoConverge); + Result := NextYield; +end; + +{-------------------------------------------------------} + +function YieldMaturity(Issue, Settlement, Maturity : TStDate; + Rate, Price : Extended; + Basis : TStBasis) : Extended; +var + DCFim, DCFsm, DCFis : Extended; +begin + if (Price <= 0.0) or (Rate < 0.0) or (Settlement < Issue) or + (Settlement >= Maturity) then + RaiseStFinError(stscFinBadArg); + DCFim := DayCountFraction(Issue, Maturity, Settlement, Maturity, + fqAnnual, Basis); + DCFsm := DayCountFraction(Settlement, Maturity, Settlement, Maturity, + fqAnnual, Basis); + DCFis := DayCountFraction(Issue, Settlement, Settlement, Maturity, + fqAnnual, Basis); + Result := 100.0 * (1.0 + Rate * DCFim); + Result := Result / (Price + 100.0 * Rate * DCFis); + Result := (Result - 1.0) / DCFsm; +end; + + + +initialization + RecipLn10 := 1.0 / Ln(10.0); +end. + diff --git a/components/systools/source/run/sthash.pas b/components/systools/source/run/sthash.pas new file mode 100644 index 000000000..bc8365b76 --- /dev/null +++ b/components/systools/source/run/sthash.pas @@ -0,0 +1,995 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StHASH.PAS 4.04 *} +{*********************************************************} +{* SysTools: Hash table class *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +{Notes: + - Generally the same as STDICT.PAS, but the hash table is + keyed on elements of arbitrary type rather than just strings. + + - Also manages an LRU counter and updates each node's LRU when + it is added or accessed. If the maximum allowed number of nodes + in the table is exceeded, the least recently used node is + automatically removed from the table. By default, MaxLongInt + nodes can be in the table so the automatic removal logic does + not come into play. When a node is automatically removed, the + NodeRemoved virtual method is called to notify the program + that the node is being removed. +} + +unit StHASH; + +interface + +uses + SysUtils, + Classes, + {$IFNDEF FPC} + {$IFDEF ThreadSafe} + Windows, + {$ENDIF} + {$ENDIF} + StConst, + StBase; + +type + TStHashNode = class(TStNode) +{.Z+} + protected + hnNext : TStHashNode; {Next node in hash list} + hnValue: Pointer; {Pointer to value of element} + hnValSize : Cardinal; {Size of hnValue memory block} + FLRU : LongInt; {LRU counter of this node} + + function GetValue : Pointer; + +{.Z-} + public + constructor CreateNode(const AValue; AValSize : Cardinal; AData : Pointer); + virtual; + {-Initialize node} + destructor Destroy; override; + {-Free name string and destroy node} + + property Value : Pointer + read GetValue; + property LRU : LongInt + read FLRU + write FLRU; + end; + +{.Z+} + THashArray = array[0..(MaxInt div SizeOf(TStHashNode))-1] of TStHashNode; + PHashArray = ^THashArray; +{.Z-} + + THashFunc = function (const V; Size : Integer) : Integer; + + TStHashTable = class(TStContainer) +{.Z+} + protected + {property instance variables} + FValSize : Cardinal; {Size of each element in table} + FHashSize : Integer; {Bins in hash array} + FEqual : TUntypedCompareFunc; {Element compare function} + FHash : THashFunc; {Hash function} + FMaxNodes : LongInt; {Max nodes allowed in table} + + {private instance variables} + htHeads : PHashArray; {Pointer to head of node lists} + htTails : PHashArray; {Pointer to tail of node lists} + htLRU : LongInt; {LRU counter} + htIgnoreDups : Boolean; {Ignore duplicates during Join?} + + {protected undocumented methods} + procedure htInsertNode(H : Integer; This : TStHashNode); + procedure htIterate(Action : TIterateFunc; OtherData : Pointer; + var H : Integer; var Prev, This : TStHashNode); + procedure htSetEqual(E : TUntypedCompareFunc); + procedure htSetHash(H : THashFunc); + procedure htSetHashSize(Size : Integer); + procedure htSetMaxNodes(Nodes : LongInt); + procedure htMoveToFront(H : Integer; Prev, This : TStHashNode); + procedure htFindNode(const V; var H : Integer; + var Prev, This : TStHashNode); + procedure htUpdateLRU(This : TStHashNode); + procedure htDeleteOldestNode; + +{.Z-} + public + constructor Create(AValSize : Cardinal; AHashSize : Integer); virtual; + {-Initialize an empty hash table} + destructor Destroy; override; + {-Destroy a hash table} + + procedure LoadFromStream(S : TStream); override; + {-Read a hash table and its data from a stream} + procedure StoreToStream(S : TStream); override; + {-Write a hash table and its data to a stream} + + procedure Clear; override; + {-Remove all nodes from container but leave it instantiated} + + function Exists(const V; var Data : Pointer) : Boolean; + {-Return True and the Data pointer if V is in the hash table} + procedure Add(const V; Data : Pointer); + {-Add new value and Data to the hash table} + procedure Delete(const V); + {-Delete a value from the hash table} + procedure Update(const V; Data : Pointer); + {-Update the data for an existing element} + function Find(Data : Pointer; var V) : Boolean; + {-Return True and the element value that matches Data} + + procedure Assign(Source: TPersistent); override; + {-Assign another hash table's contents to this one} + procedure Join(H : TStHashTable; IgnoreDups : Boolean); + {-Add hash table H into this one and dispose H} + + function Iterate(Action : TIterateFunc; + OtherData : Pointer) : TStHashNode; + {-Call Action for all the nodes, returning the last node visited} + + procedure NodeRemoved(const V; Data : Pointer); virtual; + {-Called when a not recently used node is removed from the table} + + function BinCount(H : Integer) : LongInt; + {-Return number of names in a hash bin (for testing)} + + property Equal : TUntypedCompareFunc + {-Change the string compare function; only for an empty table} + read FEqual + write htSetEqual; + + property Hash : THashFunc + {-Change the hash function; only for an empty table} + read FHash + write htSetHash; + + property HashSize : Integer + {-Change the hash table size; preserves existing elements} + read FHashSize + write htSetHashSize; + + property ValSize : Cardinal + {-Read the size of each element in the table} + read FValSize; + + property MaxNodes : LongInt + {-Change the maximum nodes in the table} + read FMaxNodes + write htSetMaxNodes; + end; + +{======================================================================} + +implementation + +{$IFDEF ThreadSafe} +var + ClassCritSect : TRTLCriticalSection; +{$ENDIF} + +procedure EnterClassCS; +begin +{$IFDEF ThreadSafe} + EnterCriticalSection(ClassCritSect); +{$ENDIF} +end; + +procedure LeaveClassCS; +begin +{$IFDEF ThreadSafe} + LeaveCriticalSection(ClassCritSect); +{$ENDIF} +end; + + + +{----------------------------------------------------------------------} + +constructor TStHashNode.CreateNode(const AValue; AValSize : Cardinal; + AData : Pointer); +begin + Create(AData); + hnValSize := AValSize; + GetMem(hnValue, AValSize); + Move(AValue, hnValue^, AValSize); +end; + +destructor TStHashNode.Destroy; +begin + if Assigned(hnValue) then + FreeMem(hnValue, hnValSize); + inherited Destroy; +end; + +function TStHashNode.GetValue : Pointer; +begin + Result := hnValue; +end; + +{----------------------------------------------------------------------} + +procedure TStHashTable.Add(const V; Data : Pointer); +var + H : Integer; + P, T : TStHashNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + htFindNode(V, H, P, T); + if Assigned(T) then + RaiseContainerError(stscDupNode); + htInsertNode(H, TStHashNode.CreateNode(V, FValSize, Data)); +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +function AssignNode(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; far; +var + HashNode : TStHashNode absolute Node; + OurHashTbl : TStHashTable absolute OtherData; +begin + OurHashTbl.Add(HashNode.Value^, HashNode.Data); + Result := true; +end; + +procedure TStHashTable.Assign(Source: TPersistent); +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + {The only container that we allow to be assigned to a hash table + is... another hash table} + if (Source is TStHashTable) then begin + Clear; + FValSize := TStHashTable(Source).ValSize; + TStHashTable(Source).Iterate(AssignNode, Self); + end + else + inherited Assign(Source); +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + + +function TStHashTable.BinCount(H : Integer) : LongInt; +var + C : LongInt; + T : TStHashNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + C := 0; + T := htHeads^[H]; + while Assigned(T) do begin + inc(C); + T := T.hnNext; + end; + Result := C; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.Clear; +var + TableSize : Cardinal; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if FCount <> 0 then begin + Iterate(DestroyNode, nil); + FCount := 0; + htLRU := 0; + TableSize := FHashSize*SizeOf(TStHashNode); + FillChar(htHeads^, TableSize, 0); + FillChar(htTails^, TableSize, 0); + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +constructor TStHashTable.Create(AValSize : Cardinal; AHashSize : Integer); +begin + if AValSize = 0 then + RaiseContainerError(stscBadSize); + + CreateContainer(TStHashNode, 0); + + FValSize := AValSize; + FMaxNodes := MaxLongInt; + + {allocate hash table by assigning to the HashSize property} + HashSize := AHashSize; +end; + +procedure TStHashTable.Delete(const V); +var + H : Integer; + P, T : TStHashNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + htFindNode(V, H, P, T); + if Assigned(T) then begin + if Assigned(P) then + P.hnNext := T.hnNext + else + htHeads^[H] := T.hnNext; + if T = htTails^[H] then + htTails^[H] := P; + DestroyNode(Self, T, nil); + Dec(FCount); + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +destructor TStHashTable.Destroy; +var + TableSize : Cardinal; +begin + if conNodeProt = 0 then + Clear; + TableSize := FHashSize*SizeOf(TStHashNode); + if Assigned(htHeads) then + FreeMem(htHeads, TableSize); + if Assigned(htTails) then + FreeMem(htTails, TableSize); + IncNodeProtection; + inherited Destroy; +end; + +function TStHashTable.Exists(const V; var Data : Pointer) : Boolean; +var + H : Integer; + P, T : TStHashNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + htFindNode(V, H, P, T); + if Assigned(T) then begin + htMoveToFront(H, P, T); + htUpdateLRU(T); + Result := True; + Data := T.Data; + end else + Result := False; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +function FindNodeData(Container : TStContainer; Node : TStNode; + OtherData : Pointer) : Boolean; far; +begin + Result := (OtherData <> Node.Data); +end; + +function TStHashTable.Find(Data : Pointer; var V) : Boolean; +var + H : Integer; + P, T : TStHashNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + htIterate(FindNodeData, Data, H, P, T); + if Assigned(T) then begin + htMoveToFront(H, P, T); + htUpdateLRU(T); + Result := True; + Move(T.Value^, V, FValSize); + end else + Result := False; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.htDeleteOldestNode; + {-Find and delete the hash node with the smallest LRU counter} +var + H, MinH : Integer; + MinLRU : LongInt; + T, P : TStHashNode; +begin + if FCount <> 0 then begin + MinLRU := MaxLongInt; + MinH := 0; + for H := 0 to FHashSize-1 do + if Assigned(htTails^[H]) and (htTails^[H].LRU <= MinLRU) then begin + MinH := H; + MinLRU := htTails^[H].LRU; + end; + + {notify the application} + with htTails^[MinH] do + NodeRemoved(hnValue^, Data); + + {destroy the node} + DestroyNode(Self, htTails^[MinH], nil); + dec(FCount); + + {remove the node} + if htTails^[MinH] = htHeads^[MinH] then begin + {only node in this bin} + htTails^[MinH] := nil; + htHeads^[MinH] := nil; + end else begin + {at least two nodes in this bin} + T := htHeads^[MinH]; + P := nil; + while T <> htTails^[MinH] do begin + P := T; + T := T.hnNext; + end; + P.hnNext := nil; + htTails^[MinH] := P; + end; + end; +end; + +procedure TStHashTable.htFindNode(const V; var H : Integer; + var Prev, This : TStHashNode); +var + P, T : TStHashNode; +begin + if not(Assigned(FEqual) and Assigned(FHash)) then + RaiseContainerError(stscNoCompare); + + Prev := nil; + This := nil; + H := FHash(V, HashSize); + T := htHeads^[H]; + P := nil; + while Assigned(T) do begin + if FEqual(V, T.Value^) = 0 then begin + Prev := P; + This := T; + Exit; + end; + P := T; + T := T.hnNext; + end; + + {not found} + This := nil; +end; + +procedure TStHashTable.htInsertNode(H : Integer; This : TStHashNode); + {-Insert node This at front of hash bin H} +var + P : TStHashNode; +begin + P := htHeads^[H]; + htHeads^[H] := This; + if not Assigned(htTails^[H]) then + htTails^[H] := This; + This.hnNext := P; + htUpdateLRU(This); + Inc(FCount); + if FCount > FMaxNodes then + htDeleteOldestNode; +end; + +procedure TStHashTable.htIterate(Action : TIterateFunc; OtherData : Pointer; + var H : Integer; var Prev, This : TStHashNode); + {-Internal version of Iterate that returns more details} +var + AHash : Integer; + P, T, N : TStHashNode; +begin + if FCount <> 0 then begin + for AHash := 0 to FHashSize-1 do begin + T := htHeads^[AHash]; + P := nil; + while Assigned(T) do begin + N := T.hnNext; + if Action(Self, T, OtherData) then begin + P := T; + T := N; + end else begin + H := AHash; + Prev := P; + This := T; + Exit; + end; + end; + end; + end; + This := nil; +end; + +procedure TStHashTable.htMoveToFront(H : Integer; Prev, This : TStHashNode); + {-Move This to front of list} +begin + if Assigned(Prev) then begin + Prev.hnNext := This.hnNext; + This.hnNext := htHeads^[H]; + htHeads^[H] := This; + if This = htTails^[H] then + htTails^[H] := Prev; + end; +end; + +procedure TStHashTable.htSetEqual(E : TUntypedCompareFunc); +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if Count = 0 then + FEqual := E; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.htSetHash(H : THashFunc); +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + if Count = 0 then + FHash := H; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.htSetHashSize(Size : Integer); +var + HInx : integer; + TableSize: LongInt; + Temp : TStHashNode; + Node : TStHashNode; + OldHeads : PHashArray; + OldTails : PHashArray; + OldSize : Integer; + OldCount : Integer; + OldDisposeData : TDisposeDataProc; + OldOnDisposeData : TStDisposeDataEvent; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + {calculate the new table size} + TableSize := LongInt(Size) * sizeof(TStHashNode); + if (Size <= 0) {or (TableSize > MaxBlockSize)} then + RaiseContainerError(stscBadSize); + + {only do something if there's something to do} + if (Size <> FHashSize) then begin + + {Notes: lots of things are going to be happening here: new + allocations, nodes copied from the old table to the new, + etc. Ideally if an exception is raised we would like to + restore the hash table to the state it was in + originally, before letting the exception escape} + + {save enough data about the current state of the table to + allow restoring in case of an exception} + OldHeads := htHeads; + OldTails := htTails; + OldSize := FHashSize; + OldCount := FCount; + OldDisposeData := DisposeData; + OldOnDisposeData := OnDisposeData; + + {reset Self's data} + htHeads := nil; + htTails := nil; + FHashSize := Size; + FCount := 0; + DisposeData := nil; + OnDisposeData := nil; + + {from this point, exceptions can occur with impunity...} + try + {allocate the new head and tail tables} + htHeads := AllocMem(TableSize); + htTails := AllocMem(TableSize); + + {if there is data to transfer, do so} + if (OldHeads <> nil) and (OldCount <> 0) then begin + for HInx := 0 to pred(OldSize) do begin + Node := OldHeads^[HInx]; + while Assigned(Node) do begin + Add(Node.hnValue^, Node.Data); + Node := Node.hnNext; + end; + end; + end; + + {now all the data has been transferred, we can + destroy the old table} + if (OldHeads <> nil) then begin + for HInx := 0 to pred(OldSize) do begin + Node := OldHeads^[HInx]; + while Assigned(Node) do begin + Temp := Node; + Node := Node.hnNext; + Temp.Free; + end; + end; + FreeMem(OldHeads, OldSize * sizeof(TStHashNode)); + end; + if (OldTails <> nil) then + FreeMem(OldTails, OldSize * sizeof(TStHashNode)); + + {restore the disposedata routines} + DisposeData := OldDisposeData; + OnDisposeData := OldOnDisposeData; + + except + {destroy the new data} + if (htHeads <> nil) then begin + for HInx := 0 to pred(FHashSize) do begin + Node := htHeads^[HInx]; + while Assigned(Node) do begin + Temp := Node; + Node := Node.hnNext; + Temp.Free; + end; + end; + FreeMem(htHeads, TableSize); + end; + if (htTails <> nil) then + FreeMem(htTails, TableSize); + {restore the old data} + htHeads := OldHeads; + htTails := OldTails; + FHashSize := OldSize; + FCount := OldCount; + DisposeData := OldDisposeData; + OnDisposeData := OldOnDisposeData; + {reraise the exception} + raise; + end; + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.htSetMaxNodes(Nodes : LongInt); +begin + if Nodes < 1 then + RaiseContainerError(stscBadSize); + FMaxNodes := Nodes; + while FCount > FMaxNodes do + htDeleteOldestNode; +end; + +type + TMinNode = record + MLRU : LongInt; + MNode : TStHashNode; + end; + PMinNode = ^TMinNode; + +function FindMinPositiveNode(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; far; + {-Used to find the smallest non-negative LRU in the table} +begin + with PMinNode(OtherData)^, TStHashNode(Node) do + if (LRU >= 0) and (LRU <= MLRU) then begin + MLRU := LRU; + MNode := TStHashNode(Node); + end; + Result := True; +end; + +function NegateNodeLRU(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; far; + {-Used to negate the LRU values of all nodes in the table} +begin + with TStHashNode(Node) do + LRU := -LRU; + Result := True; +end; + +procedure TStHashTable.htUpdateLRU(This : TStHashNode); + {-Reassign all LRU values sequentially in their existing order} +var + MinNode : TMinNode; +begin + inc(htLRU); + This.LRU := htLRU; + if htLRU = MaxLongInt then begin + {scan table and pack LRU values} + htLRU := 0; + repeat + inc(htLRU); + MinNode.MLRU := MaxLongInt; + MinNode.MNode := nil; + Iterate(FindMinPositiveNode, @MinNode); + if not Assigned(MinNode.MNode) then + break; + {nodes already visited are set to a negative value} + {depends on never having an LRU of zero} + MinNode.MNode.LRU := -htLRU; + until False; + {negative values are made positive} + Iterate(NegateNodeLRU, nil); + end; +end; + +function TStHashTable.Iterate(Action : TIterateFunc; + OtherData : Pointer) : TStHashNode; +var + H : Integer; + P : TStHashNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + htIterate(Action, OtherData, H, P, Result); +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +function JoinNode(Container : TStContainer; + Node : TStNode; + OtherData : Pointer) : Boolean; far; + {-Used to add nodes from another table into this one} +var + H : Integer; + P, T : TStHashNode; +begin + Result := True; + with TStHashTable(OtherData) do begin + htFindNode(TStHashNode(Node).Value^, H, P, T); + if Assigned(T) then + if htIgnoreDups then begin + Node.Free; + Exit; + end else + RaiseContainerError(stscDupNode); + htInsertNode(H, TStHashNode(Node)); + end; +end; + +procedure TStHashTable.Join(H : TStHashTable; IgnoreDups : Boolean); +begin +{$IFDEF ThreadSafe} + EnterClassCS; + EnterCS; + H.EnterCS; + try +{$ENDIF} + htIgnoreDups := IgnoreDups; + H.Iterate(JoinNode, Self); + {dispose of D, but not its nodes} + H.IncNodeProtection; + H.Free; +{$IFDEF ThreadSafe} + finally + H.LeaveCS; + LeaveCS; + LeaveClassCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.LoadFromStream(S : TStream); +var + Data, Value : Pointer; + AValSize : Cardinal; + Reader : TReader; + StreamedClass : TPersistentClass; + StreamedNodeClass : TPersistentClass; + StreamedClassName : string; + StreamedNodeClassName : string; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + Clear; + Reader := TReader.Create(S, 1024); + try + with Reader do begin + StreamedClassName := ReadString; + StreamedClass := GetClass(StreamedClassName); + if not Assigned(StreamedClass) then + RaiseContainerErrorFmt(stscUnknownClass, [StreamedClassName]); + if (StreamedClass <> Self.ClassType) then + RaiseContainerError(stscWrongClass); + StreamedNodeClassName := ReadString; + StreamedNodeClass := GetClass(StreamedNodeClassName); + if not Assigned(StreamedNodeClass) then + RaiseContainerErrorFmt(stscUnknownNodeClass, [StreamedNodeClassName]); + if (StreamedNodeClass <> conNodeClass) then + RaiseContainerError(stscWrongNodeClass); + + AValSize := ReadInteger; + if AValSize <> FValSize then + RaiseContainerError(stscBadSize); + HashSize := ReadInteger; + FMaxNodes := ReadInteger; + GetMem(Value, FValSize); + try + ReadListBegin; + while not EndOfList do begin + ReadBoolean; + Read(Value^, FValSize); + Data := DoLoadData(Reader); + Add(Value^, Data); + end; + ReadListEnd; + finally + FreeMem(Value, FValSize); + end; + end; + finally + Reader.Free; + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.NodeRemoved(const V; Data : Pointer); +begin + {does nothing by default} +end; + +procedure TStHashTable.StoreToStream(S : TStream); +var + H : Integer; + Walker : TStHashNode; + Writer : TWriter; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + Writer := TWriter.Create(S, 1024); + try + with Writer do begin + WriteString(Self.ClassName); + WriteString(conNodeClass.ClassName); + WriteInteger(FValSize); + WriteInteger(FHashSize); + WriteInteger(FMaxNodes); + WriteListBegin; + if Count <> 0 then + for H := 0 to FHashSize-1 do begin + Walker := htHeads^[H]; + while Assigned(Walker) do begin + {writing the True boolean prevents false termination of the + list if Value's first byte is zero when the stream is + loaded into another hash table} + WriteBoolean(True); + Write(Walker.Value^, FValSize); + DoStoreData(Writer, Walker.Data); + Walker := Walker.hnNext; + end; + end; + WriteListEnd; + end; + finally + Writer.Free; + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +procedure TStHashTable.Update(const V; Data : Pointer); +var + H : Integer; + P, T : TStHashNode; +begin +{$IFDEF ThreadSafe} + EnterCS; + try +{$ENDIF} + htFindNode(V, H, P, T); + if Assigned(T) then begin + htMoveToFront(H, P, T); + htUpdateLRU(T); + T.Data := Data; + end; +{$IFDEF ThreadSafe} + finally + LeaveCS; + end; +{$ENDIF} +end; + +{$IFDEF ThreadSafe} +initialization + Windows.InitializeCriticalSection(ClassCritSect); +finalization + Windows.DeleteCriticalSection(ClassCritSect); +{$ENDIF} +end. diff --git a/components/systools/source/run/stinistm.pas b/components/systools/source/run/stinistm.pas new file mode 100644 index 000000000..41dea4eeb --- /dev/null +++ b/components/systools/source/run/stinistm.pas @@ -0,0 +1,594 @@ +// Upgraded to Delphi 2009: Sebastian Zierer +// FIXME: TStAnsiTextStream + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StIniStm.pas 4.04 *} +{*********************************************************} +{* SysTools: .INI file-like stream class *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$include StDefine.inc} + +unit StIniStm; + + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils, Classes, StStrms; + +type + + TStIniStream = class(TObject) + private + FAnsiStream : TStAnsiTextStream; + FSections : TStringList; + procedure GetSecStrings(Strs: TStrings); + protected + procedure GotoSection(const Section : String); + procedure UpdateSections; + procedure WriteSectionName(const Section : String); + procedure WriteValue(const Key, Value : String); + public + constructor Create(aStream : TStream); + destructor Destroy; override; + + function SectionExists(const Section : String): Boolean; + function ReadString(const Section, Ident, Default : String) : String; + procedure WriteString(const Section, Ident, Value : String); + procedure WriteSection(const Section : String; Strings: TStrings); + procedure ReadSection(const Section : String; Strings: TStrings); + procedure ReadSections(Strings: TStrings); + procedure ReadSectionValues(const Section : String; Strings: TStrings); + procedure EraseSection(const Section : String); + procedure DeleteKey(const Section, Ident : String); + function ValueExists(const Section, Ident : String): Boolean; + end; + +procedure SplitNameValue(const Line : string; var Name, Value : string); {!!.04} + +implementation + +{!!.04 - Added } +procedure SplitNameValue(const Line : string; var Name, Value : string); +var + P : Integer; +begin + P := Pos('=', Line); + if P < 1 then begin + Name := Line; + Value := ''; + Exit; + end; + + Name := Copy(Line, 1, P-1); + Value := Copy(Line, P+1, Length(Line) - P); +end; +{!!.04 - Added End} + +function IsHeader(const AString : String) : Boolean; +{ see if passed in text looks like an .INI header } +var + Temp : String; +begin + if AString = '' then begin + Result := False; + Exit; + end; + + Temp := Trim(AString); + Result := (Temp[1] = '[') and (Temp[Length(Temp)] = ']') +end; + + +{ TStIniStream } + +constructor TStIniStream.Create(aStream: TStream); +begin + inherited Create; + FAnsiStream := TStAnsiTextStream.Create(aStream); + FSections := TStringList.Create; + FSections.Sorted := True; + FSections.Duplicates := dupIgnore; + + if aStream.Size > 0 then { not an empty stream } + UpdateSections; +end; + +destructor TStIniStream.Destroy; +begin + FSections.Free; + FAnsiStream.Free; + inherited Destroy; +end; + + +procedure TStIniStream.DeleteKey(const Section, Ident : String); +{ delete specified item from Section } +var + SecStrs : TStringList; + SecIdx : Integer; + MS : TMemoryStream; + TS : TStAnsiTextStream; + i, Idx : Integer; +begin + SecStrs := TStringList.Create; + MS := TMemoryStream.Create; + TS := TStAnsiTextStream.Create(MS); + + try + { locate and read section } + GotoSection(Section); + GetSecStrings(SecStrs); + Idx := SecStrs.IndexOfName(Ident); + + if Idx > - 1 then begin + { remove desired key } + SecStrs.Delete(Idx); + + { locate subsequent section } + SecIdx := FSections.IndexOf(Section); + if SecIdx < Pred(FSections.Count) then begin + GotoSection(FSections[SecIdx+1]); + + { copy remaining sections } + while not FAnsiStream.AtEndOfStream do + TS.WriteLine(FAnsiStream.ReadLine); + end; + { else this is the last section } + + { seek back and truncate } + GotoSection(Section); + FAnsiStream.Size := FAnsiStream.Position; +// FAnsiStream.SetSize(FAnsiStream.Position); + + { write updated section } + WriteSectionName(Section); + for i := 0 to Pred(SecStrs.Count) do + FAnsiStream.WriteLine(SecStrs[i]); + FAnsiStream.Stream.Seek(0, soFromEnd); + + { append saved subsequent sections } + TS.SeekLine(0); + while not TS.AtEndOfStream do + FAnsiStream.WriteLine(TS.ReadLine); + + end; { if Ident > -1 } + { else the Ident doesn't exist so don't alter anything } + + finally + SecStrs.Free; + TS.Free; + MS.Free; + end; +end; + +procedure TStIniStream.EraseSection(const Section : String); +{ erase specified section from Ini data } +var + SecIdx : Integer; + MS : TMemoryStream; + TS : TStAnsiTextStream; +begin + MS := TMemoryStream.Create; + TS := TStAnsiTextStream.Create(MS); + + { locate section } + SecIdx := FSections.IndexOf(Section); + + { if section found } + if SectionExists(Section) then begin + try + { if this is not the last section } + if (SecIdx < Pred(FSections.Count)) then begin + { locate subsequent section } + GotoSection(FSections[SecIdx+1]); + + { copy remaining sections to temporary stream} + while not FAnsiStream.AtEndOfStream do + TS.WriteLine(FAnsiStream.ReadLine); + end; + { else this is the last section } + + { locate section to delete and truncate } + GotoSection(Section); + FAnsiStream.Size := FAnsiStream.Position; +// FAnsiStream.SetSize(FAnsiStream.Position); + + { append saved subsequent sections } + TS.SeekLine(0); + while not TS.AtEndOfStream do + FAnsiStream.WriteLine(TS.ReadLine); + + finally + TS.Free; + MS.Free; + end; + UpdateSections; + end; + { else section doesn't exist, do nothing } +end; + +procedure TStIniStream.GetSecStrings(Strs : TStrings); +{ read strings from a section, preserving comments and blanks } +var + LineVal : String; +begin + { assume we're at the start of a section } + FAnsiStream.ReadLine; { skip section header } + + LineVal := FAnsiStream.ReadLine; + while not (FAnsiStream.AtEndOfStream) and not (IsHeader(LineVal)) do begin + Strs.Add(LineVal); { add it to the list } + LineVal := FAnsiStream.ReadLine; { get next line } + end; +end; + +procedure TStIniStream.GotoSection(const Section: String); +{ position stream to requested section header } +var + Idx : Integer; +begin + Idx := FSections.IndexOf(Section); + if Idx > -1 then + FAnsiStream.SeekLine(Integer(FSections.Objects[Idx])); +end; + +procedure TStIniStream.ReadSectionValues(const Section : String; + Strings: TStrings); +{ return <Name>=<Value> pairs of requested Section in Strings } +var + Strs : TStringList; + LineVal : String; + i : Integer; +begin + if not Assigned(Strings) then Exit; + + Strs := TStringList.Create; + if SectionExists(Section) then begin { section exists } + Strings.Clear; + try + { locate section } + GotoSection(Section); + + { retrieve section contents, comments, blank lines and all } + GetSecStrings(Strs); + + { iterate section lines looking for entries } + for i := 0 to Pred(Strs.Count) do begin + LineVal := Strs[i]; + if (Trim(LineVal) <> '') and (Trim(LineVal[1]) <> ';') and (Pos('=', LineVal) > 0) then {!!.02} + { not empty and not a comment and at least superficially resembles a + <Name>=<Value> pair } + Strings.Add(Trim(LineVal)); { add it to the list } {!!.02} + end; + finally + Strs.Free; + end; + end; + { else section doesn't exist, do nothing } +end; + +procedure TStIniStream.ReadSections(Strings: TStrings); +var + i : Integer; +begin + if not Assigned(Strings) then Exit; + + { omit the pseudo section } + for i := 1 to Pred(FSections.Count) do + Strings.Add(Trim(FSections[i])); {!!.02} +end; + +procedure TStIniStream.ReadSection(const Section : String; + Strings: TStrings); +{ return Name strings for all entries in requested section } +var + SecStrs : TStringList; + i : Integer; + LineVal, Name : String; +begin + if not Assigned(Strings) then Exit; + + SecStrs := TStringList.Create; + try +// ReadSection(Section, SecStrs); +{!!.02 - Rewritten } + Strings.Clear; + { locate section } + GotoSection(Section); + + { retrieve section contents, comments, blank lines and all } + GetSecStrings(SecStrs); + + { iterate section lines looking for entries } + for i := 0 to Pred(SecStrs.Count) do begin + LineVal := SecStrs[i]; + if (Trim(LineVal) <> '') and (Trim(LineVal[1]) <> ';') and (Pos('=', LineVal) > 0) then begin + { not empty and not a comment and at least superficially resembles a + <Name>=<Value> pair } + SplitNameValue(LineVal, Name, LineVal); + Strings.Add(Trim(Name)); + end; + end; + +// for i := 0 to Pred(SecStrs.Count) do +// Strings.Add(SecStrs.Names[i]); +{!!.02 - Rewritten End } + + + finally + SecStrs.Free; + end; +end; + +function TStIniStream.ReadString(const Section, Ident, + Default : String) : String; +{ +return a particular string selected by Ident from Section +if empty or doesn't exist, return Default +} +var + SecStrs : TStringList; +begin + SecStrs := TStringList.Create; + try + ReadSectionValues(Section, SecStrs); {!!.04} + + Result := SecStrs.Values[Ident]; + if Result = '' then + Result := Default; + + finally + SecStrs.Free; + end; +end; + +function TStIniStream.SectionExists(const Section : String): Boolean; +{ returns True if Section exists in section list, False otherwise } +begin + Result := FSections.IndexOf(Section) > -1; +end; + +procedure TStIniStream.UpdateSections; +{ refresh Sections list } +var + i : Integer; + Line : String; +begin + i := 0; + FSections.Clear; + FAnsiStream.SeekLine(0); + + { pseudo section to account for any comments or whitespace prior to first + real section in data } + FSections.AddObject('[]', TObject(0)); + + { iterate data looking for section headers: '[blah]' } + while not FAnsiStream.AtEndOfStream do begin + Line := Trim(FAnsiStream.ReadLine); + { if it looks like a header } + if IsHeader(Line) then + { add it to the list with a line index } + FSections.AddObject(Copy(Line, 2, Length(Line) - 2), TObject(i)); + { go to next line } + Inc(i); + end; +end; + +function TStIniStream.ValueExists(const Section, Ident : String): Boolean; +{ +see if requested section contains requested Ident +implies "<Ident>=" exists in section, not that there's necessarily any +explicit Value associated, i.e. Value may be blank +} +var + SecStrs : TStringList; + i : Integer; +begin + Result := False; + SecStrs := TStringList.Create; + try + { get section } + ReadSection(Section, SecStrs); + + { see if Ident exists in Names collection } + for i := 0 to Pred(SecStrs.Count) do + if SecStrs.Names[i] = Ident then begin + Result := True; + Break; + end; + finally + SecStrs.Free; + end; +end; + +procedure TStIniStream.WriteString(const Section, Ident, Value : String); +{ write individual string value to IniStream } +var + SecStrs : TStringList; + SecIdx : Integer; + MS : TMemoryStream; + TS : TStAnsiTextStream; + i : Integer; +begin + if SectionExists(Section) then begin + SecStrs := TStringList.Create; + MS := TMemoryStream.Create; + TS := TStAnsiTextStream.Create(MS); + + try + { locate and read section } + GotoSection(Section); + GetSecStrings(SecStrs); + + { locate subsequent section } + SecIdx := FSections.IndexOf(Section); + if SecIdx < Pred(FSections.Count) then begin + GotoSection(FSections[SecIdx+1]); + + { copy remaining sections } + while not FAnsiStream.AtEndOfStream do + TS.WriteLine(FAnsiStream.ReadLine); + end; + { else this is the last section } + + { seek back and truncate } + GotoSection(Section); + FAnsiStream.Size := FAnsiStream.Position; + +// FAnsiStream.SetSize(FAnsiStream.Position); + + { insert new value } + SecStrs.Add(Ident + '=' + Value); + + { write updated section } + WriteSectionName(Section); + for i := 0 to Pred(SecStrs.Count) do + FAnsiStream.WriteLine(SecStrs[i]); + FAnsiStream.Stream.Seek(0, soFromEnd); + + { append saved subsequent sections } + TS.SeekLine(0); + while not TS.AtEndOfStream do + FAnsiStream.WriteLine(TS.ReadLine); + + finally + SecStrs.Free; + TS.Free; + MS.Free; + end; + + end + else begin { no such section exists, append new one } + FAnsiStream.Seek(0, soFromEnd); + WriteSectionName(Section); + WriteValue(Ident, Value); + UpdateSections; + end; + +end; + +procedure TStIniStream.WriteSectionName(const Section: String); +{ write section header at current location } +begin + FAnsiStream.WriteLine('[' + Section + ']'); +end; + +procedure TStIniStream.WriteValue(const Key, Value: String); +{ write <Name>=<Value> pair at current location } +begin + FAnsiStream.WriteLine(Key + '=' + Value); +end; + +procedure TStIniStream.WriteSection(const Section: String; + Strings: TStrings); +{ write entire section described by Strings } +var + SecStrs : TStringList; + SecIdx : Integer; + MS : TMemoryStream; + TS : TStAnsiTextStream; + i : Integer; + L : LongInt; + Name : String; +begin + if not Assigned(Strings) then Exit; + + if SectionExists(Section) then begin + SecStrs := TStringList.Create; + MS := TMemoryStream.Create; + TS := TStAnsiTextStream.Create(MS); + + try + { locate and read section } + GotoSection(Section); + GetSecStrings(SecStrs); + + { locate subsequent section } + SecIdx := FSections.IndexOf(Section); + if SecIdx < Pred(FSections.Count) then begin + GotoSection(FSections[SecIdx+1]); + + { copy remaining sections } + while not FAnsiStream.AtEndOfStream do + TS.WriteLine(FAnsiStream.ReadLine); + end; + { else this is the last section } + + { seek back and truncate } + GotoSection(Section); + FAnsiStream.Size := FAnsiStream.Position; +// FAnsiStream.SetSize(FAnsiStream.Position); + + { update section } + for i := 0 to Pred(Strings.Count) do begin + Name := Strings.Names[i]; + if SecStrs.IndexOfName(Name) > -1 then { entry exists, change value } + SecStrs.Values[Name] := Strings.Values[Name] + else { new entry, just append it } + SecStrs.Add(Strings[i]); + end; + + { write updated section } + WriteSectionName(Section); + for i := 0 to Pred(SecStrs.Count) do + FAnsiStream.WriteLine(SecStrs[i]); + FAnsiStream.Stream.Seek(0, soFromEnd); + + { append saved subsequent sections } + TS.SeekLine(0); + while not TS.AtEndOfStream do + FAnsiStream.WriteLine(TS.ReadLine); + + finally + SecStrs.Free; + TS.Free; + MS.Free; + end; + + end + else begin { no such section exists, append new one } + L := FAnsiStream.LineCount; + FAnsiStream.Seek(0, soFromEnd); + WriteSectionName(Section); + FSections.AddObject(Section, TObject(L+1)); + for i := 0 to Pred(Strings.Count) do + FAnsiStream.WriteLine(Strings[i]); +// UpdateSections; + end; +end; + +end. diff --git a/components/systools/source/run/stmath.pas b/components/systools/source/run/stmath.pas new file mode 100644 index 000000000..28388f26d --- /dev/null +++ b/components/systools/source/run/stmath.pas @@ -0,0 +1,175 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StMath.pas 4.04 *} +{*********************************************************} +{* SysTools: Miscellaneous math functions *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit StMath; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils, StDate, StBase, StConst; + +const + RadCor : Double = 57.29577951308232; {number of degrees in a radian} + +{$IFNDEF UseMathUnit} + function IntPower(Base : Extended; Exponent : Integer): Extended; + {-Raise Base to an integral power Exponent} + + function Power(Base, Exponent : Extended) : Extended; + {-Raise Base to an arbitrary power Exponent} +{$ENDIF} + +function StInvCos(X : Double): Double; + {-Returns the ArcCos of Y} + +function StInvSin(Y : Double): Double; + {-Returns the ArcSin of Y} + + function StInvTan2(X, Y : Double) : Double; + {-Returns the ArcTangent of Y / X} + +function StTan(A : Double) : Double; + {-Returns the Tangent of A} + + +{-------------------------------------------------------} + +implementation + +{$IFNDEF UseMathUnit} + function IntPower(Base : Extended; Exponent : Integer): Extended; + var + Y : Integer; + begin + Y := Abs(Exponent); + Result := 1; + while (Y > 0) do begin + while (not Odd(Y)) do begin + Y := Y shr 1; + Base := Base * Base; + end; + Dec(Y); + Result := Result * Base; + end; + if (Exponent < 0) then + Result := 1 / Result; + end; + + {-------------------------------------------------------} + + function Power(Base, Exponent: Extended): Extended; + begin + if (Exponent = 0) then + Result := 1 + else if (Base = 0) and (Exponent > 0) then + Result := 0 + else if (Frac(Exponent) = 0) and (Abs(Exponent) <= MaxInt) then + Result := IntPower(Base, Trunc(Exponent)) + else + Result := Exp(Exponent * Ln(Base)); + end; +{$ENDIF} + +{-------------------------------------------------------} + +function StTan(A : Double) : Double; +var + C, S : Double; +begin + C := Cos(A); + S := Sin(A); + if (Abs(C) >= 5E-12) then + Result := S / C + else if (C < 0) then + Result := 5.0e-324 + else + Result := 1.7e+308; +end; + +{-------------------------------------------------------} + +function StInvTan2(X, Y : Double) : Double; +begin + if (Abs(X) < 5.0E-12) then begin + if (X < 0) then + Result := 3 * Pi / 2 + else + Result := Pi / 2; + end else begin + Result := ArcTan(Y / X); + if (X < 0) then + Result := Result + Pi + else if (Y < 0) then + Result := Result + 2 * Pi; + end; +end; + +{-------------------------------------------------------} + +function StInvSin(Y : Double): Double; +begin + if (Abs(Abs(Y) - 1) > 5.0E-12) then + Result := ArcTan(Y / Sqrt(1 - Y * Y)) + else begin + if (Y < 0) then + Result := 3 * Pi / 2 + else + Result := Pi / 2; + end; +end; + +{-------------------------------------------------------} + +function StInvCos(X : Double): Double; +begin + if (Abs(Abs(X) - 1) > 5.0E-12) then + Result := (90 / RadCor) - ArcTan(X / Sqrt(1 - X * X)) + else begin + if ((X - Pi / 2) > 0) then + Result := 0 + else + Result := Pi; + end; +end; + + +end. diff --git a/components/systools/source/run/stmoney.pas b/components/systools/source/run/stmoney.pas new file mode 100644 index 000000000..b84b415a2 --- /dev/null +++ b/components/systools/source/run/stmoney.pas @@ -0,0 +1,1530 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StMoney.pas 4.04 *} +{*********************************************************} +{* SysTools: Currency and Money Related Classes *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$include StDefine.inc} + +unit StMoney; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils, Classes, + + StConst, StBase, StStrms, StDecMth, StIniStm; + + +type +{ +; Layout of currency entries +[ISOCode] +Name=Country-Currency Name +ISOName=<ISO 4217 3 Letter Currency ID> +ISOCode=<ISO 4217 3 Digit Currency Number> +UnitMajor=<Major Currency Name> +UnitMinor=<Minor Currency Name> +Ratio=<ratio of minor currency to major> +} + + TStCurrency = class(TObject) + { representation of a national currency, based on ISO 4217 specification } + private + FName: String; + FISOCode: String; + FISOName: String; + FRatio: Integer; + FUnitMajor: String; + FUnitMinor: String; + + public + { Persistence and streaming methods } + procedure LoadFromList(List : TStrings); + procedure SaveToList(List : TStrings); + + { properties } + property ISOCode: String + read FISOCode write FISOCode; + property ISOName: String + read FISOName write FISOName; + property Name: String + read FName write FName; + property Ratio: Integer + read FRatio write FRatio; + property UnitMajor: String + read FUnitMajor write FUnitMajor; + property UnitMinor: String + read FUnitMinor write FUnitMinor; + end; + + TStCurrencyList = class (TObject) + { collection of national currencies } + private + FItems: TStringList; + protected {private} + function GetCount: Integer; + function GetCurrency(const ISOName : String): TStCurrency; + function GetItem(Index : Integer): TStCurrency; + procedure SetCurrency(const ISOName : String; Value: TStCurrency); + procedure SetItem(Index : Integer; Value: TStCurrency); + + procedure FreeCurrencyByIndex(Index : Integer); + public + constructor Create; + destructor Destroy; override; + + { Access and Update Methods } + procedure Add(ACurrency : TStCurrency); + procedure Clear; + function Contains(ACurrency : TStCurrency): Boolean; + function ContainsName(const ISOName : String): Boolean; + procedure Delete(const ISOName: String); + function IndexOf(const ISOName : String) : Integer; + + { Persistence and streaming methods } + procedure LoadFromFile(const AFileName: TFileName); + procedure LoadFromStream(AStream: TStream); + procedure SaveToFile(const AFileName: TFileName); + procedure SaveToStream(AStream: TStream); + + { properties } + property Count : Integer + read GetCount; + property Currencies[const ISOName : String]: TStCurrency + read GetCurrency write SetCurrency; + property Items[Index : Integer] : TStCurrency + read GetItem write SetItem; default; + end; + + +{ +Conversion Methods +=================== +When converting money of one currency into money of another currency, three +conversion methods are commonly encountered: + +1) +"Triangular": the source currency amount is converted to an intermediate +currency amount, then the intermediate currency amount is converted to +the target amount. + +Note: This is the method required by members of the European Monetary +Union (EMU), for converting among national currencies that are transitioning +to the Euro; the Euro should be used as the Intermediate currency for such +conversions. + +2) +"Multiply" the source currency amount is multiplied by a conversion Rate +to obtain the target currency amount. + +3) +"Divide" the source currency amount is divided by a conversion Rate to +obtain the target currency amount. +} + TStConversionType = (ctUnknown, ctTriangular, ctMultiply, ctDivide); + + TStGetRateUpdateEvent = procedure (Sender: TObject; NewRate : TStDecimal; + var NewDate : TDateTime) of object; +{ +; Layout of exchange entries +[SRC:TRG] +source=SRC +target=TRG +; empty/ignored if not a triangular exchange +intermediate=XXX +rate=xxx +; error if tri and intermediate not set +type=<tri|mul|div> +date=<date> +} + + TStExchangeRate = class (TObject) + { particular Exchange Rate between two currencies } + private + FRate: TStDecimal; + FSource: String; + FTarget : String; + FIntermediate : String; + FConversionType : TStConversionType; + FDateUpdated : TDateTime; + FOnGetRateUpdate: TStGetRateUpdateEvent; + procedure SetRate(const Value: TStDecimal); + public + constructor Create; + destructor Destroy; override; + + { Access and Update Methods } + procedure Assign(ARate : TStExchangeRate); + procedure Clear; + procedure Convert(Amount, Result: TStDecimal); + function Equals(aRate : TStExchangeRate) : Boolean; + function IsValid : Boolean; + function SameSourceAndTarget(aRate : TStExchangeRate) : Boolean; + procedure Update; + + { Persistence and streaming methods } + procedure LoadFromList(List : TStrings); + procedure SaveToList(List : TStrings); + + { properties } + property ConversionType : TStConversionType + read FConversionType write FConversionType; + property DateUpdated : TDateTime + read FDateUpdated write FDateUpdated; + property Intermediate : String + read FIntermediate write FIntermediate; + property Rate : TStDecimal + read FRate write SetRate; + property Source : String + read FSource write FSource; + property Target : String + read FTarget write FTarget; + + { events } + property OnGetRateUpdate : TStGetRateUpdateEvent + read FOnGetRateUpdate write FOnGetRateUpdate; + end; + + TStExchangeRateList = class (TObject) + { collection of currency conversions (TStExchangeRate) } + private + FRates : TStringList; + protected {private} + procedure DeleteRate(Index: Integer); + function GetCount: Integer; + function GetRate(const Source, Target: String): TStExchangeRate; + function GetItem(Index: Integer): TStExchangeRate; + function MakeEntry(const Source, Target: String): String; virtual; + + procedure ConvertPrim(const aSource, aTarget : string; + aAmount : TStDecimal; + aAllowTriangular : boolean); + public + constructor Create; + destructor Destroy; override; + + { Access and Update Methods } + procedure Add(ARate : TStExchangeRate); + procedure AddByValues(const Source, Target, Intermediate: String; + Rate: Double; ConversionType: TStConversionType; DateUpdated: TDateTime); + procedure Assign(AList : TStExchangeRateList); + procedure Clear; + function Contains(ARate : TStExchangeRate) : Boolean; + function ContainsByName(const Source, Target : String) : Boolean; + procedure Convert(const Source, Target : String; + Amount, Result : TStDecimal); + procedure Delete(ARate : TStExchangeRate); + procedure DeleteByName(const Source, Target : String); + procedure UpdateRate(const Source, Target : String; Rate : TStDecimal); + + { Persistence and streaming methods } + procedure LoadFromFile(const AFileName: TFileName); + procedure LoadFromStream(AStream: TStream); + procedure SaveToFile(const AFileName: TFileName); + procedure SaveToStream(AStream: TStream); + + { properties } + property Count : Integer + read GetCount; + { Returns the number of exchange rates in this table. } + property Items[Index : Integer] : TStExchangeRate + read GetItem; + { access to all of the exchange rates in the collection by numeric index } + property Rates[const Source, Target : String] : TStExchangeRate + read GetRate; + { access to all of the exchange rates in the collection by Source and Target } + end; + + TStMoney = class (TObject) + { representation of an amount of Currency and operations on same } + private + FAmount : TStDecimal; + FCurrency : String; + FExchangeRates : TStExchangeRateList; + + function GetAsFloat: Double; + function GetAsString: String; + procedure SetAmount(const Value: TStDecimal); + procedure SetAsFloat(const Value: Double); + procedure SetAsString(const Value: String); + procedure Validate(Source, Operand, Result: TStMoney); + function ValidateCurrencies(Source, Dest: TStMoney) : Boolean; + public + constructor Create; + destructor Destroy; override; + procedure Assign(AMoney : TStMoney); + + { basic math operations } + procedure Abs(Result : TStMoney); + procedure Add(Addend, Sum : TStMoney); + procedure Divide(Divisor : Double; Quotient : TStMoney); + procedure DivideByDecimal(Divisor : TStDecimal; Quotient : TStMoney); + procedure Multiply(Multiplier : Double; Product : TStMoney); + procedure MultiplyByDecimal(Multiplier : TStDecimal; Product : TStMoney); + procedure Negate(Result : TStMoney); + procedure Subtract(Subtrahend, Remainder : TStMoney); + + { logical comparisons } + function Compare(CompareTo : TStMoney): Integer; + function IsEqual(AMoney : TStMoney): Boolean; + function IsGreaterThan(AMoney : TStMoney): Boolean; + function IsGreaterThanOrEqual(AMoney : TStMoney): Boolean; + function IsLessThan(AMoney : TStMoney): Boolean; + function IsLessThanOrEqual(AMoney : TStMoney): Boolean; + function IsNegative: Boolean; + function IsNotEqual(AMoney : TStMoney): Boolean; + function IsPositive: Boolean; + function IsZero: Boolean; + + { Conversion Methods } + procedure Convert(const Target : String; Result : TStMoney); + procedure Round(Method : TStRoundMethod; Decimals : Integer; Result : TStMoney); + { See definition of TStRoundMethod in the StDecMth unit for more + information on rounding } + + { properties } + property Amount: TStDecimal + read FAmount write SetAmount; + property AsFloat: Double + read GetAsFloat write SetAsFloat; + property AsString: String + read GetAsString write SetAsString; + property Currency: String + read FCurrency write FCurrency; + property ExchangeRates : TStExchangeRateList + read FExchangeRates write FExchangeRates; + end; + +implementation + +var + ExchBaseDate : TDateTime; // the base date for exchange rates + +{ TStCurrency } + +procedure TStCurrency.LoadFromList(List : TStrings); +{ +assign currency properties from a set of <Name>=<Value> pairs + +BuildItem expects data in the form: + +Name=Country-Currency Name +ISOName=<ISO 4217 3 Letter Currency ID> +ISOCode=<ISO 4217 3 Digit Currency Number> +UnitMajor=<Major Currency Name> +UnitMinor=<Minor Currency Name> +Ratio=<ratio of minor currency to major> +} +begin + if Assigned(List) then begin + FName := List.Values['Name']; + FISOCode := List.Values['ISOCode']; + FISOName := List.Values['ISOName']; + FUnitMajor := List.Values['UnitMajor']; + FUnitMinor := List.Values['UnitMinor']; + FRatio := StrToIntDef(List.Values['Ratio'], 100); + end; +end; + +procedure TStCurrency.SaveToList(List : TStrings); +{ write Currency data to <Name>=<Value> pairs for persistence } +begin + if Assigned(List) then begin + List.Clear; + List.Add('Name=' + FName); + List.Add('ISOCode=' + FISOCode); + List.Add('ISOName=' + FISOName); + List.Add('UnitMajor=' + FUnitMajor); + List.Add('UnitMinor=' + FUnitMinor); + List.Add('Ratio=' + IntToStr(FRatio)); + end; +end; + +{ TStCurrencyList } + +constructor TStCurrencyList.Create; +begin + inherited Create; + FItems := TStringList.Create; + FItems.Sorted := True; + FItems.Duplicates := dupIgnore; +end; + +destructor TStCurrencyList.Destroy; +begin + Clear; + FItems.Free; + inherited Destroy; +end; + +procedure TStCurrencyList.Add(ACurrency: TStCurrency); +{ add a new currency to the list } +begin + if Assigned(ACurrency) then + FItems.AddObject(ACurrency.ISOName, ACurrency); +end; + +procedure TStCurrencyList.Clear; +{ Clear the list of currencies } +var + i: Integer; +begin + for i := Pred(FItems.Count) downto 0 do + FreeCurrencyByIndex(i); +end; + +function TStCurrencyList.Contains(ACurrency: TStCurrency): Boolean; +{ returns true if there's an entry for such a currency } +begin + Result := False; + if Assigned(ACurrency) then + Result := FItems.IndexOf(ACurrency.ISOName) >= 0; +end; + +function TStCurrencyList.ContainsName(const ISOName: String): Boolean; +{ returns true if there's an entry for such a currency ID } +begin + Result := FItems.IndexOf(ISOName) >= 0; +end; + +procedure TStCurrencyList.Delete(const ISOName: String); +{ delete the requested currency from the list } +begin + FreeCurrencyByIndex(FItems.IndexOf(ISOName)); +end; + +procedure TStCurrencyList.FreeCurrencyByIndex(Index: Integer); +{ release a currency by the requested numeric index in the list } +begin + { if index in range } + if (0 <= Index) and (Index < FItems.Count) then begin + { free StCurrency data at that index } + (FItems.Objects[Index] as TStCurrency).Free; + { delete item from list } + FItems.Delete(Index); + end; + { else, item doesn't exist, so do nothing } +end; + +function TStCurrencyList.GetCount : Integer; +{ just return count of maintained items } +begin + Result := FItems.Count; +end; + +function TStCurrencyList.GetCurrency(const ISOName: String): TStCurrency; +{ +return reference to requested currency item indexed by ISOName +returns nil if item doesn't exist +} +var + Index : Integer; +begin + { find index of item } + Index := FItems.IndexOf(ISOName); + { return item as a TStCurrency reference, or nil if it wasn't found } + if (Index >= 0) then + Result := GetItem(Index) + else + Result := nil; +end; + +function TStCurrencyList.GetItem(Index : Integer): TStCurrency; +{ +return reference to requested currency item indexed by position in list +returns nil if item doesn't exist +} +begin + if not ((0 <= Index) and (Index < FItems.Count)) then + raise EStException.CreateResFmtTP(stscBadIndex, [IntToStr(Index)], 0); + + Result := (FItems.Objects[Index] as TStCurrency); +end; + +function TStCurrencyList.IndexOf(const ISOName: String): Integer; +{ +locate index of requested item in list, +returns -1 if item doesn't exist +} +begin + Result := FItems.IndexOf(ISOName); +end; + +procedure TStCurrencyList.LoadFromFile(const AFileName: TFileName); +var + FS : TFileStream; +begin + FS := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); + try + LoadFromStream(FS); + finally + FS.Free; + end; +end; + +procedure TStCurrencyList.LoadFromStream(AStream : TStream); +var + IniStr : TStIniStream; + Currencies, Section : TStrings; + ACurrency : TStCurrency; + i : Integer; +begin + {clear out the current currency items} + Clear; + + IniStr := nil; + Currencies := nil; + Section := nil; + ACurrency := nil; + try + IniStr := TStIniStream.Create(AStream); + Currencies := TStringList.Create; + Section := TStringList.Create; + { create an "index" of the sections } + IniStr.ReadSections(Currencies); + + { read a currency definition } + for i := 0 to Pred(Currencies.Count) do begin + { get settings as .INI style items } + IniStr.ReadSectionValues(Currencies[i], Section); + + { create a new currency item } + ACurrency := TStCurrency.Create; + + { set its properties } + ACurrency.LoadFromList(Section); + + { add it to the list } + FItems.AddObject(ACurrency.ISOName, ACurrency); + ACurrency := nil; + end; + finally + IniStr.Free; + Section.Free; + Currencies.Free; + // note: this only does something if either the LoadFromList or + // AddObject calls failed + ACurrency.Free; + end; +end; + +procedure TStCurrencyList.SaveToFile(const AFileName: TFileName); +var + FS : TFileStream; +begin + if not FileExists(AFileName) then begin + FS := TFileStream.Create(AFileName, fmCreate); + FS.Free; + end; + + FS := TFileStream.Create(AFileName, fmOpenWrite or fmShareDenyNone); + try + SaveToStream(FS); + finally + FS.Free; + end; +end; + +procedure TStCurrencyList.SaveToStream(AStream : TStream); +var + IniStr : TStIniStream; + Strs : TStringList; + i : Integer; +begin + IniStr := nil; + Strs := nil; + try + IniStr := TStIniStream.Create(AStream); + Strs := TStringList.Create; + for i := 0 to Pred(FItems.Count) do begin + { clear the string list to contain the ccy definition } + Strs.Clear; + { get item properties as string list } + (FItems.Objects[i] as TStCurrency).SaveToList(Strs); + { add new section to .INI data } + IniStr.WriteSection(FItems[i], Strs); + end; + finally + Strs.Free; + IniStr.Free; + end; +end; + +procedure TStCurrencyList.SetCurrency(const ISOName: String; + Value: TStCurrency); +var + Idx : Integer; +begin + { locate item } + Idx := FItems.IndexOf(ISOName); + if (Idx >= 0) then + SetItem(Idx, Value); +end; + +procedure TStCurrencyList.SetItem(Index : Integer; + Value: TStCurrency); +begin + if not ((0 <= Index) and (Index < FItems.Count)) then + raise EStException.CreateResFmtTP(stscBadIndex, [IntToStr(Index)], 0); + + if Assigned(Value) then begin + { release current currency info } + (FItems.Objects[Index] as TStCurrency).Free; + { replace with new info } + FItems.Objects[Index] := Value; + end; +end; + + +{ TStMoney } + +constructor TStMoney.Create; +begin + inherited Create; + FAmount := TStDecimal.Create; +end; + +destructor TStMoney.Destroy; +begin + FAmount.Free; + inherited Destroy; +end; + +procedure TStMoney.Abs(Result : TStMoney); +{ Returns a new money which has the absolute value of this money's amount. } +begin + Result.Assign(Self); + Result.Amount.Abs; +end; + +procedure TStMoney.Add(Addend, Sum : TStMoney); +begin + Validate(Self, Addend, Sum); + Sum.Assign(Self); + Sum.Amount.Add(Addend.Amount); +end; + +procedure TStMoney.Assign(AMoney : TStMoney); +begin + if Assigned(AMoney) then begin + Amount.Assign(AMoney.Amount); + Currency := AMoney.Currency; + ExchangeRates := AMoney.ExchangeRates; + end; +end; + +function TStMoney.Compare(CompareTo : TStMoney): Integer; +{ +Compares this money to the specified money. + +Returns <0 if this money is less than the other money, 0 if they are equal, +and >0 if it is greater + +Note: Currencies must also be the same +} +begin + Validate(Self, CompareTo, Self); + Result := Amount.Compare(CompareTo.Amount); +end; + +procedure TStMoney.Convert(const Target : String; Result : TStMoney); +{ +Converts the value to a different currency, utilizes TStExchangeRateList +} +begin + { check that exchange rates are available } + if not Assigned(ExchangeRates) then + raise EStException.CreateResTP(stscMoneyNoExchangeRatesAvail, 0); + + { check validity of operands and result } + if not Assigned(Result) then + raise EStException.CreateResTP(stscMoneyNilResult, 0); + + Result.Assign(Self); + ExchangeRates.Convert(Currency, Target, Amount, Result.Amount); +end; + +procedure TStMoney.DivideByDecimal(Divisor : TStDecimal; Quotient : TStMoney); +{ Returns a new money which is the quotient of the money divided by +the decimal divisor. } +begin + if not Assigned(Divisor) then + raise EStException.CreateResTP(stscMoneyNilParameter, 0); + + if not Assigned(Quotient) then + raise EStException.CreateResTP(stscMoneyNilResult, 0); + + Quotient.Assign(Self); + Quotient.Amount.Divide(Divisor); +end; + +procedure TStMoney.Divide(Divisor : Double; Quotient : TStMoney); +{ Returns a new money which is the quotient of the money divided by +the floating point divisor. } +var + DecDiv : TStDecimal; +begin + DecDiv := TStDecimal.Create; + try + DecDiv.AssignFromFloat(Divisor); + DivideByDecimal(DecDiv, Quotient); + finally + DecDiv.Free; + end; +end; + +function TStMoney.GetAsFloat: Double; +{ return money amount as a Floating point value } +begin + Result := Amount.AsFloat; +end; + +function TStMoney.GetAsString: String; +{ return money amount as a string } +begin + Result := Amount.AsString; +end; + +function TStMoney.IsEqual(AMoney : TStMoney): Boolean; +{ Returns true if this money and the specified money are equal } +begin + Result := Compare(AMoney) = 0; +end; + +function TStMoney.IsGreaterThan(AMoney : TStMoney): Boolean; +{ Returns true if this money's amount is greater than that of the specified money. } +begin + Result := Compare(AMoney) > 0; +end; + +function TStMoney.IsGreaterThanOrEqual(AMoney : TStMoney): Boolean; +{ Returns true if this money's amount is greater than or equal to the specified money. } +begin + Result := Compare(AMoney) >= 0; +end; + +function TStMoney.IsPositive : Boolean; +{ Returns true if this money's amount is greater than zero. } +begin + Result := Amount.IsPositive; +end; + +function TStMoney.IsZero: Boolean; +{ Returns true if this money's amount is equal to zero. } +begin + Result := Amount.IsZero; +end; + +function TStMoney.IsLessThan(AMoney : TStMoney): Boolean; +{ Returns true if this money's amount is less than that of the specified money. } +begin + Result := Compare(AMoney) < 0; +end; + +function TStMoney.IsLessThanOrEqual(AMoney : TStMoney): Boolean; +{ Returns true if this money's amount is less than or equal to that of the specified money. } +begin + Result := Compare(AMoney) <= 0; +end; + +function TStMoney.IsNegative: Boolean; +{ Returns true if this money's amount is less than zero. } +begin + Result := Amount.IsNegative; +end; + +function TStMoney.IsNotEqual(AMoney : TStMoney): Boolean; +{ Returns true if this money and the specified money are not equal } +begin + Result := Compare(AMoney) <> 0; +end; + +procedure TStMoney.MultiplyByDecimal(Multiplier : TStDecimal; + Product : TStMoney); +{ Returns a new money which is the product of the money and the decimal value. } +begin + if not Assigned(Multiplier) then + raise EStException.CreateResTP(stscMoneyNilParameter, 0); + + if not Assigned(Product) then + raise EStException.CreateResTP(stscMoneyNilResult, 0); + + Product.Assign(Self); + Product.Amount.Multiply(Multiplier); +end; + +procedure TStMoney.Multiply(Multiplier : Double; Product : TStMoney); +{ Returns a new money which is the product of the money and the floating point value. } +var + MulDec : TStDecimal; +begin + MulDec := TStDecimal.Create; + try + MulDec.AssignFromFloat(Multiplier); + MultiplyByDecimal(MulDec, Product); + finally + MulDec.Free; + end; +end; + +procedure TStMoney.Negate(Result : TStMoney); +{ Returns a new money which is the negation of this money's amount. } +begin + if not Assigned(Result) then + raise EStException.CreateResTP(stscMoneyNilResult, 0); + + Result.Assign(Self); + Result.Amount.ChangeSign; +end; + +procedure TStMoney.Round(Method : TStRoundMethod; Decimals : Integer; Result : TStMoney); +{ +Returns a new money with the rounded value of this money using the specified accuracy. +and using the specified rounding method + +See definition of TStRoundMethod in the StDecMth unit for more +information on rounding +} +begin + if not Assigned(Result) then + raise EStException.CreateResTP(stscMoneyNilResult, 0); + + Result.Assign(Self); + Result.Amount.Round(Method, Decimals); +end; + +procedure TStMoney.SetAmount(const Value: TStDecimal); +begin + Amount.Assign(Value); +end; + +procedure TStMoney.SetAsFloat(const Value: Double); +begin + Amount.AssignFromFloat(Value); +end; + +procedure TStMoney.SetAsString(const Value: String); +begin + Amount.AsString := Value; +end; + +procedure TStMoney.Subtract(Subtrahend, Remainder : TStMoney); +{ Returns a new money which is the difference between this money and the given money. } +begin + Validate(Self, Subtrahend, Remainder); + Remainder.Assign(Self); + Remainder.Amount.Subtract(Subtrahend.Amount); +end; + +function TStMoney.ValidateCurrencies(Source, Dest : TStMoney) : Boolean; +begin + Result := Source.Currency = Dest.Currency; +end; + +procedure TStMoney.Validate(Source, Operand, Result : TStMoney); +begin + { check validity of operands and result } + if not Assigned(Source) or not Assigned(Operand) then + raise EStException.CreateResTP(stscMoneyNilParameter, 0); + + if not Assigned(Result) then + raise EStException.CreateResTP(stscMoneyNilResult, 0); + + if not ValidateCurrencies(Source, Operand) then + raise EStException.CreateResTP(stscMoneyCurrenciesNotMatch, 0); +end; + +{ TStExchangeRate } + +constructor TStExchangeRate.Create; +begin + inherited Create; + FRate := TStDecimal.Create; + Clear; +end; + +destructor TStExchangeRate.Destroy; +begin + FRate.Free; + inherited Destroy; +end; + +procedure TStExchangeRate.Assign(ARate: TStExchangeRate); +begin + if Assigned(ARate) then begin + Source := ARate.Source; + Target := ARate.Target; + Intermediate := ARate.Intermediate; + ConversionType := ARate.ConversionType; + DateUpdated := ARate.DateUpdated; + Rate.Assign(ARate.Rate); + end else + begin + Clear; + end; +end; + +procedure TStExchangeRate.Clear; +{ clear item fields } +begin + FSource := ''; + FTarget := ''; + FIntermediate := ''; + FConversionType := ctMultiply; + FDateUpdated := ExchBaseDate; + FRate.SetToOne; +end; + +procedure TStExchangeRate.Convert(Amount, Result: TStDecimal); +{ convert supplied amount using current ConversionType and Exchange Rate } +begin + {the parameters must be present} + if not Assigned(Amount) or not Assigned(Result) then + raise EStException.CreateResTP(stscMoneyNilParameter, 0); + + {the exchange rate must be valid} + if not IsValid then + raise EStException.CreateResTP(stscMoneyInvalidExchRate, 0); + + {set the result equal to the amount prior to converting it} + Result.Assign(Amount); + + case ConversionType of + { multiplication conversion } + ctMultiply : + begin + Result.Multiply(Rate); + end; + + { division conversion } + ctDivide : + begin + Result.Divide(Rate); + end; + + { triangular conversion } + ctTriangular : + begin + {this can't be done by a single exchange rate} + raise EStException.CreateResTP(stscMoneyInvalidTriangleExchange, 0); + end; + + else + raise EStException.CreateResTP(stscMoneyInvalidExchangeParams, 0); + end; { case } +end; + +function TStExchangeRate.Equals(aRate: TStExchangeRate): Boolean; +{ +Returns true if this exchange rate and specified exchange rate have +identical Exchange types, Source currencies, Target currencies, +and conversion Rates or are both Triangular exchanges with the same +Source, Target, and Intermediate currencies +} +var + CurrenciesMatch, TypesMatch : Boolean; +begin + Result := False; + if not Assigned(aRate) then Exit; + + { check if currencies match } + CurrenciesMatch := (AnsiCompareText(Source, aRate.Source) = 0) and + (AnsiCompareText(Target, aRate.Target) = 0); + + { check if exchange types match } + TypesMatch := (ConversionType = aRate.ConversionType); + + if TypesMatch and CurrenciesMatch then + case ConversionType of + ctTriangular : { both triangular } + { equal if same intermediate currency } + Result := (FIntermediate = aRate.FIntermediate); + + ctMultiply, + ctDivide : { both multiply or divide } + { equal if same conversion rate } + Result := (Rate.Compare(aRate.Rate) = 0); + else + raise EStException.CreateResTP(stscMoneyInvalidExchangeParams, 0); + end; { case } +end; + +function TStExchangeRate.IsValid: Boolean; +{ +Checks to see if this exchange rate has its source, target and Rate +fields set to non-default values, or if a Triangular exchange, that +the intermediate currency is set +} +begin + {assume the exchange rate is invalid} + Result := false; + + {the source cannot be empty} + if (Source = '') then + Exit; + + {the target cannot be empty} + if (Target = '') then + Exit; + + {the source and target must be different} + if (AnsiCompareText(Source, Target) = 0) then + Exit; + + {for a multiply/divide conversion, the rate must be > 0.0} + if (ConversionType = ctMultiply) or (ConversionType = ctDivide) then begin + Result := FRate.IsPositive; + Exit; + end; + + {for a triangular conversion, the intermediate currency must be set + and cannot be equal to either Source or Target to avoid infinite + loops in TStExchangeList.Convert <g>} + if (ConversionType = ctTriangular) then begin + if (Intermediate = '') then + Exit; + if (AnsiCompareText(Source, Intermediate) = 0) then + Exit; + if (AnsiCompareText(Target, Intermediate) = 0) then + Exit; + Result := true; + Exit; + end; + + {otherwise the exchange rate is invalid} +end; + +function MakeXChgStr(ConversionType : TStConversionType) : String; +{ convert TStConversionType to string for persistence } +begin + case ConversionType of + ctTriangular : Result := 'tri'; + ctMultiply : Result := 'mul'; + ctDivide : Result := 'div'; + else + raise Exception.Create('Unknown conversion type'); + end; { case } +end; + +function MakeXChg(const XchStr : String) : TStConversionType; +{ convert persistence string to TStConversionType } +begin + if (AnsiCompareText(XchStr, 'mul') = 0) then + Result := ctMultiply + else if (AnsiCompareText(XchStr, 'div') = 0) then + Result := ctDivide + else if (AnsiCompareText(XchStr, 'tri') = 0) then + Result := ctTriangular + else begin + raise Exception.Create('Unknown conversion type in INI file'); + Result := ctUnknown; + end; +end; + +procedure ReplaceCh(var S : String; aFromCh : Char; aToCh : Char); +var + i : integer; +begin + {replace the first occurrence of aFromCh with aToCh in string S} + for i := 0 to length(S) do + if (S[i] = aFromCh) then begin + S[i] := aToCh; + Exit; + end; +end; + +procedure TStExchangeRate.LoadFromList(List: TStrings); +{ +set item properties from Exchange Rate data +expects data in the format: + +source=<source currency> +target=<target currency> +intermediate=<intermediate currency> +rate=<exchange rate> +type=<tri|mul|div> +date=<date of setting> +} +var + Str : String; + DayCount : integer; + ec : integer; +begin + if Assigned(List) then begin + Clear; + FSource := List.Values['source']; + FTarget := List.Values['target']; + FIntermediate := List.Values['intermediate']; + FConversionType := MakeXChg(List.Values['type']); + + Str := List.Values['date']; + Val(Str, DayCount, ec); + if (ec <> 0) then + DayCount := 0; + FDateUpdated := ExchBaseDate + DayCount; + + Str := List.Values['rate']; + if Str = '' then + FRate.SetToOne + else begin + {the INI file stores rates with a decimal *point*; if the locale + uses something else (eg, a comma) we'll need to switch it for + the AsString property, which obeys the locale} + if ({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator <> '.') then + ReplaceCh(Str, '.', {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator); + FRate.AsString := Str; + end; + end; +end; + +function TStExchangeRate.SameSourceAndTarget( + aRate: TStExchangeRate): Boolean; +{ +Tests whether the specified rate has the same source and target currencies. +Returns True of the Source and Target currencies are the same, False otherwise +} +begin + Result := False; + if Assigned(aRate) then + Result := (AnsiCompareText(Source, aRate.Source) = 0) and + (AnsiCompareText(Target, aRate.Target) = 0); +end; + +procedure TStExchangeRate.SaveToList(List: TStrings); +{ create persistent representation of item } +var + Str : String; + DayCount : integer; +begin + if Assigned(List) then begin + List.Clear; + List.Add('source=' + FSource); + List.Add('target=' + FTarget); + List.Add('intermediate=' + FIntermediate); + Str := FRate.AsString; + if ({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator <> '.') then + ReplaceCh(Str, {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator, '.'); + List.Add('rate=' + Str); + List.Add('type=' + MakeXChgStr(FConversionType)); + DayCount := trunc(FDateUpdated - ExchBaseDate); + if DayCount < 0 then + DayCount := 0; + List.Add('date=' + IntToStr(DayCount)); + end; +end; + +procedure TStExchangeRate.SetRate(const Value: TStDecimal); +begin + FRate.Assign(Value); +end; + +procedure TStExchangeRate.Update; +{ fire update event } +var + NewDate : TDateTime; +begin + if Assigned(FOnGetRateUpdate) then begin + NewDate := DateUpdated; + FOnGetRateUpdate(Self, Rate, NewDate); + DateUpdated := NewDate; + end; +end; + + +{ TStExchangeRateList } +constructor TStExchangeRateList.Create; +begin + inherited Create; + FRates := TStringList.Create; + FRates.Sorted := True; + FRates.Duplicates := dupIgnore; +end; + +destructor TStExchangeRateList.Destroy; +begin + Clear; + FRates.Free; + inherited Destroy; +end; + +procedure TStExchangeRateList.Add(ARate: TStExchangeRate); +{ +Adds the given exchange rate to the list + +Since FRates list is set for dupIgnore, if Rate already exists, the +new values will be discarded + +To modify an existing rate, use the Rates property or the UpdateRate +method, or delete the existing Rate and re-add it +} +begin + if Assigned(ARate) then + FRates.AddObject(MakeEntry(ARate.Source, ARate.Target), ARate); +end; + +procedure TStExchangeRateList.AddByValues(const Source, Target, + Intermediate : String; Rate : Double; ConversionType : TStConversionType; + DateUpdated : TDateTime); +{ +Create new rate with provided characteristics and add it to the list + +Since FRates list is set for dupIgnore, if Rate already exists, the +new values will be discarded + +To modify an existing rate, use the Rates property or the UpdateRate +method, or delete the existing Rate and re-add it +} +var + TempRate : TStExchangeRate; +begin + TempRate := TStExchangeRate.Create; + TempRate.Source := Source; + TempRate.Target := Target; + TempRate.Intermediate := Intermediate; + TempRate.ConversionType := ConversionType; + TempRate.DateUpdated := DateUpdated; + TempRate.Rate.AssignFromFloat(Rate); + Add(TempRate); +end; + +procedure TStExchangeRateList.Assign(AList: TStExchangeRateList); +var + i : Integer; +begin + if Assigned(AList) then begin + { if Rate Lists already point to same list then don't do anything } + if FRates = AList.FRates then Exit; + + { empty list } + Clear; + + { add items from new list } + for i := 0 to Pred(AList.Count) do + Add(AList.Items[i]); + end; +end; + +procedure TStExchangeRateList.Clear; +{ Clears all of the exchange rates from this table. } +var + i : Integer; +begin + for i := Pred(FRates.Count) downto 0 do begin + DeleteRate(i); + end; +end; + +function TStExchangeRateList.Contains( + ARate: TStExchangeRate): Boolean; +{ +Returns true if an exchange rate already exists with this rate's source, +target pair. +} +begin + Result := False; + if Assigned(ARate) then + Result := ContainsByName(ARate.Source, ARate.Target); +end; + +function TStExchangeRateList.ContainsByName(const Source, + Target: String): Boolean; +{ +Returns true if an exchange rate already exists with this one's +source and target ISOName Strings +} +begin + Result := FRates.IndexOf(MakeEntry(Source, Target)) >= 0; +end; + +procedure TStExchangeRateList.Convert(const Source, Target: String; + Amount, Result: TStDecimal); +{ +convert Amount from Source currency to Target currency, +return new value in Result +} +begin + {Amount and Result must be created} + if (Amount = nil) or (Result = nil) then + raise EStException.CreateResTP(stscMoneyInvalidExchangeParams, 0); + + {set the result value equal to the amount being converted} + Result.Assign(Amount); + + {convert, allowing triangular exchanges} + ConvertPrim(Source, Target, Result, true); +end; + +procedure TStExchangeRateList.ConvertPrim(const aSource, aTarget : string; + aAmount : TStDecimal; + aAllowTriangular : boolean); +var + Rate : TStExchangeRate; +begin + { do we have an entry for a Source->Target conversion? } + if not ContainsByName(aSource, aTarget) then + raise EStException.CreateResFmtTP(stscMoneyNoSuchExchange, + [aSource, aTarget], 0); + + {get the exchange rate} + Rate := Rates[aSource, aTarget]; + + {for a simple multiply or divide conversion, the Rate object can + handle that by itself} + if (Rate.ConversionType = ctMultiply) or + (Rate.ConversionType = ctDivide) then begin + Rate.Convert(aAmount, aAmount); + Exit; + end; + + {if a triangular exchange is not allowed, raise an error} + if not aAllowTriangular then + raise EStException.CreateResTP(stscMoneyTriExchUsesTriExch, 0); + + {if the exchange rate is not triangular, raise an error} + if (Rate.ConversionType <> ctTriangular) then + raise EStException.CreateResTP(stscMoneyInvalidExchangeParams, 0); + + {the conversion is triangular: check the intermediate currency} + if (Rate.Intermediate = '') then + raise EStException.CreateResTP(stscMoneyInvalidExchangeParams, 0); + + {check to see if we have the two exchange rates} + if (not ContainsByName(aSource, Rate.Intermediate)) or + (not ContainsByName(Rate.Intermediate, aTarget)) then + raise EStException.CreateResFmtTP(stscMoneyMissingIntermediateRate, + [aSource, aTarget], 0); + + {convert the amount from the Source to the Intermediate currency, + and then the result from the Intermediate to the Target currency; + triangular exchanges are *not* allowed to avoid infinite loops} + ConvertPrim(aSource, Rate.Intermediate, aAmount, false); + ConvertPrim(Rate.Intermediate, aTarget, aAmount, false); +end; + +procedure TStExchangeRateList.Delete(ARate: TStExchangeRate); +{ +delete specified rate from list +fails silently if no matching rate exists in list +} +begin + DeleteByName(ARate.Source, ARate.Target); +end; + +procedure TStExchangeRateList.DeleteByName(const Source, + Target: String); +{ +delete rate from list as determined by Source and Target +fails silently if no matching rate exists in list +} +var + Idx : Integer; +begin + { find item in list } + Idx := FRates.IndexOf(MakeEntry(Source, Target)); + + { if it exists, remove it } + if Idx >= 0 then + DeleteRate(Idx); +end; + +procedure TStExchangeRateList.DeleteRate(Index : Integer); +{ remove Rate from list by index } +{ no error checking that Index is in Range, should be done by caller } +begin + (FRates.Objects[Index] as TStExchangeRate).Free; + FRates.Delete(Index); +end; + +function TStExchangeRateList.GetCount: Integer; +begin + Result := FRates.Count; +end; + +function TStExchangeRateList.GetItem(Index: Integer): TStExchangeRate; +{ return Exchange rate by index } +begin + if not ((0 <= Index) and (Index < FRates.Count)) then + raise EStException.CreateResFmtTP(stscBadIndex, [IntToStr(Index)], 0); + Result := (FRates.Objects[Index] as TStExchangeRate); +end; + +function TStExchangeRateList.GetRate(const Source, + Target: String): TStExchangeRate; +{ return Exchange rate by Source and Target } +var + Idx : Integer; +begin + Idx := FRates.IndexOf(MakeEntry(Source, Target)); + if Idx >= 0 then begin + Result := (FRates.Objects[Idx] as TStExchangeRate); + end + else + raise EStException.CreateResFmtTP(stscMoneyNoSuchExchange, [Source, Target], 0); +end; + +procedure TStExchangeRateList.LoadFromFile(const AFileName: TFileName); +var + FS : TFileStream; +begin + FS := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); + try + LoadFromStream(FS); + finally + FS.Free; + end; +end; + +procedure TStExchangeRateList.LoadFromStream(AStream: TStream); +{ build Rate list from stream of Rate data } +var + i : Integer; + IniStrm : TStIniStream; + Entries, Sections : TStringList; + CurRate : TStExchangeRate; +begin + IniStrm := nil; + Entries := nil; + Sections := nil; + CurRate := nil; + try + IniStrm := TStIniStream.Create(AStream); + Entries := TStringList.Create; + Sections := TStringList.Create; + { create "index" of sections } + IniStrm.ReadSections(Sections); + + { iterate sections } + for i := 0 to Pred(Sections.Count) do begin + { get settings as a list of <Name>=<Value> pairs } + IniStrm.ReadSectionValues(Sections[i], Entries); + + { build new rate item from settings } + CurRate := TStExchangeRate.Create; + CurRate.LoadFromList(Entries); + + { add to list } + Add(CurRate); + CurRate := nil; + end; + finally + Sections.Free; + Entries.Free; + IniStrm.Free; + CurRate.Free; + end; +end; + +function TStExchangeRateList.MakeEntry(const Source, Target : String) : String; +{ format conversion entry header from Source and Target } +begin + Result := Source + ':' + Target; +end; + +procedure TStExchangeRateList.SaveToFile(const AFileName: TFileName); +var + FS : TFileStream; +begin + if not FileExists(AFileName) then begin + FS := TFileStream.Create(AFileName, fmCreate); + FS.Free; + end; + + FS := TFileStream.Create(AFileName, fmOpenWrite or fmShareDenyNone); + try + SaveToStream(FS); + finally + FS.Free; + end; +end; + +procedure TStExchangeRateList.SaveToStream(AStream: TStream); +{ persist list of Rate data to a stream } +var + i : Integer; + IniStrm : TStIniStream; + Entries : TStringList; + CurRate : TStExchangeRate; +begin + IniStrm := nil; + Entries := nil; + try + IniStrm := TStIniStream.Create(AStream); + Entries := TStringList.Create; + { for each maintained Rate item } + for i := 0 to Pred(FRates.Count) do begin + + { get reference to the Rate } + CurRate := (FRates.Objects[i] as TStExchangeRate); + + { make entries for Rate } + CurRate.SaveToList(Entries); + + { write entries as a new section to INI stream } + IniStrm.WriteSection(MakeEntry(CurRate.Source, CurRate.Target), + Entries); + end; + finally + Entries.Free; + IniStrm.Free; + end; +end; + +procedure TStExchangeRateList.UpdateRate(const Source, + Target: String; Rate: TStDecimal); +{ +Modifies the exchange rate specified by the source and target +assumes rate already exists, use Add or AddByValues to add new rates +} +var + Idx : Integer; +begin + if not Assigned(Rate) then + raise EStException.CreateResTP(stscMoneyNilParameter, 0); + + Idx := FRates.IndexOf(MakeEntry(Source, Target)); + if Idx >= 0 then begin { conversion already exists for source and target } + { update Rate to reflect new rate } + (FRates.Objects[Idx] as TStExchangeRate).Rate.Assign(Rate); + end + { else no such rate } +end; + +initialization + ExchBaseDate := EncodeDate(1980, 1, 1); +end. + diff --git a/components/systools/source/run/ststrl.pas b/components/systools/source/run/ststrl.pas new file mode 100644 index 000000000..369a10c7e --- /dev/null +++ b/components/systools/source/run/ststrl.pas @@ -0,0 +1,3557 @@ +// TODO-UNICODE + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StStrL.pas 4.04 *} +{*********************************************************} +{* SysTools: Long string routines *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +unit StStrL; + +interface + +uses + {$IFDEF FPC} + LCLType, StrUtils, + {$ELSE} + Windows, + {$ENDIF} + Classes, + SysUtils, + StConst, + StBase; + +{.Z+} +type + LStrRec = record + AllocSize : Longint; + RefCount : Longint; + Length : Longint; + end; + +const + StrOffset = SizeOf(LStrRec); +{.Z-} + + {-------- Numeric conversion -----------} + +function HexBL(B : Byte) : AnsiString; + {-Return the hex string for a byte.} + +function HexWL(W : Word) : AnsiString; + {-Return the hex string for a word.} + +function HexLL(L : LongInt) : AnsiString; + {-Return the hex string for a long integer.} + +function HexPtrL(P : Pointer) : AnsiString; + {-Return the hex string for a pointer.} + +function BinaryBL(B : Byte) : AnsiString; + {-Return a binary string for a byte.} + +function BinaryWL(W : Word) : AnsiString; + {-Return the binary string for a word.} + +function BinaryLL(L : LongInt) : AnsiString; + {-Return the binary string for a long integer.} + +function OctalBL(B : Byte) : AnsiString; + {-Return an octal string for a byte.} + +function OctalWL(W : Word) : AnsiString; + {-Return an octal string for a word.} + +function OctalLL(L : LongInt) : AnsiString; + {-Return an octal string for a long integer.} + +function Str2Int16L(const S : AnsiString; var I : SmallInt) : Boolean; + {-Convert a string to an SmallInt.} + +function Str2WordL(const S : AnsiString; var I : Word) : Boolean; + {-Convert a string to a word.} + +function Str2LongL(const S : AnsiString; var I : LongInt) : Boolean; + {-Convert a string to a long integer.} + +{$IFDEF VER93} +function Str2RealL(const S : AnsiString; var R : Double) : Boolean; +{$ELSE} +function Str2RealL(const S : AnsiString; var R : Real) : Boolean; + {-Convert a string to a real.} +{$ENDIF} + +function Str2ExtL(const S : AnsiString; var R : Extended) : Boolean; + {-Convert a string to an extended.} + +function Long2StrL(L : LongInt) : String; + {-Convert an integer type to a string.} + +function Real2StrL(R : Double; Width : Byte; Places : ShortInt) : String; + {-Convert a real to a string.} + +function Ext2StrL(R : Extended; Width : Byte; Places : ShortInt) : String; + {-Convert an extended to a string.} + +function ValPrepL(const S : String) : String; + {-Prepares a string for calling Val.} + + {-------- General purpose string manipulation --------} + +function CharStrL(C : Char; Len : Cardinal) : String; + {-Return a string filled with the specified character.} + +function PadChL(const S : String; C : Char; Len : Cardinal) : String; + {-Pad a string on the right with a specified character.} + +function PadL(const S : String; Len : Cardinal) : String; + {-Pad a string on the right with spaces.} + +function LeftPadChL(const S : String; C : Char; Len : Cardinal) : String; + {-Pad a string on the left with a specified character.} + +function LeftPadL(const S : String; Len : Cardinal) : String; + {-Pad a string on the left with spaces.} + +function TrimLeadL(const S : String) : String; + {-Return a string with leading white space removed.} + +function TrimTrailL(const S : String) : String; + {-Return a string with trailing white space removed.} + +function TrimL(const S : String) : String; + {-Return a string with leading and trailing white space removed.} + +function TrimSpacesL(const S : String) : String; + {-Return a string with leading and trailing spaces removed.} + +function CenterChL(const S : String; C : Char; Len : Cardinal) : String; + {-Pad a string on the left and right with a specified character.} + +function CenterL(const S : String; Len : Cardinal) : String; + {-Pad a string on the left and right with spaces.} + +function EntabL(const S : AnsiString; TabSize : Byte) : AnsiString; + {-Convert blanks in a string to tabs.} + +function DetabL(const S : AnsiString; TabSize : Byte) : AnsiString; + {-Expand tabs in a string to blanks.} + +function ScrambleL(const S, Key : AnsiString) : AnsiString; + {-Encrypt / Decrypt string with enhanced XOR encryption.} + +function SubstituteL(const S, FromStr, ToStr : String) : String; + {-Map the characters found in FromStr to the corresponding ones in ToStr.} + +function FilterL(const S, Filters : String) : String; + {-Remove characters from a string. The characters to remove are specified in + ChSet.} + + {--------------- Word / Char manipulation -------------------------} + +function CharExistsL(const S : String; C : Char) : Boolean; + {-Determine whether a given character exists in a string. } + +function CharCountL(const S : String; C : Char) : Cardinal; + {-Count the number of a given character in a string. } + +function WordCountL(const S, WordDelims : String) : Cardinal; + {-Given an array of word delimiters, return the number of words in a string.} + +function WordPositionL(N : Cardinal; const S, WordDelims : String; + var Pos : Cardinal) : Boolean; + {-Given an array of word delimiters, set Pos to the start position of the + N'th word in a string. Result indicates success/failure.} + +function ExtractWordL(N : Cardinal; const S, WordDelims : String) : String; + {-Given an array of word delimiters, return the N'th word in a string.} + +function AsciiCountL(const S, WordDelims : String; Quote : Char) : Cardinal; + {-Return the number of words in a string.} + +function AsciiPositionL(N : Cardinal; const S, WordDelims : String; + Quote : Char; var Pos : Cardinal) : Boolean; + {-Return the position of the N'th word in a string.} + +function ExtractAsciiL(N : Cardinal; const S, WordDelims : String; + Quote : Char) : String; + {-Given an array of word delimiters, return the N'th word in a string. Any + text within Quote characters is counted as one word.} + +procedure WordWrapL(const InSt : String; var OutSt, Overlap : String; + Margin : Cardinal; PadToMargin : Boolean); + {-Wrap a text string at a specified margin.} + + {--------------- String comparison and searching -----------------} +function CompStringL(const S1, S2 : String) : Integer; + {-Compare two strings.} + +function CompUCStringL(const S1, S2 : String) : Integer; + {-Compare two strings. This compare is not case sensitive.} + +function SoundexL(const S : AnsiString) : AnsiString; + {-Return 4 character soundex of an input string.} + +(* +function MakeLetterSetL(const S : AnsiString) : Longint; + {-Return a bit-mapped long storing the individual letters contained in S.} + +{$IFDEF UNICODE} +procedure BMMakeTableL(const MatchString : UnicodeString; var BT : BTable); overload; +{$ELSE} +procedure BMMakeTableL(const MatchString : AnsiString; var BT : BTable); overload; +{$ENDIF} + {-Build a Boyer-Moore link table} + +{$IFDEF UNICODE} +function BMSearchL(var Buffer; BufLength: Cardinal; var BT: BTable; + const MatchString : String; out Pos : Cardinal) : Boolean; overload; +{$ELSE} +function BMSearchL(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : AnsiString; var Pos : Cardinal) : Boolean; overload; +{$ENDIF} + {-Use the Boyer-Moore search method to search a buffer for a string.} + +{$IFDEF UNICODE} +function BMSearchUCL(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : String ; var Pos : Cardinal) : Boolean; +{$ELSE} +function BMSearchUCL(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : AnsiString ; var Pos : Cardinal) : Boolean; +{$ENDIF} + {-Use the Boyer-Moore search method to search a buffer for a string. This + search is not case sensitive.} +*) + + {--------------- DOS pathname parsing -----------------} + +function DefaultExtensionL(const Name, Ext : String) : String; + {-Return a file name with a default extension attached.} + +function ForceExtensionL(const Name, Ext : String) : String; + {-Force the specified extension onto the file name.} + +function JustFilenameL(const PathName : String) : String; + {-Return just the filename and extension of a pathname.} + +function JustNameL(const PathName : String) : String; + {-Return just the filename (no extension, path, or drive) of a pathname.} + +function JustExtensionL(const Name : String) : String; + {-Return just the extension of a pathname.} + +function JustPathnameL(const PathName : String) : String; + {-Return just the drive and directory portion of a pathname.} + +function AddBackSlashL(const DirName : String) : String; + {-Add a default backslash to a directory name.} + +function CleanPathNameL(const PathName : String) : String; + {-Return a pathname cleaned up as DOS does it.} + +function HasExtensionL(const Name : String; var DotPos : Cardinal) : Boolean; + {-Determine if a pathname contains an extension and, if so, return the + position of the dot in front of the extension.} + + {------------------ Formatting routines --------------------} + +function CommaizeL(L : LongInt) : String; + {-Convert a long integer to a string with commas.} + +function CommaizeChL(L : Longint; Ch : Char) : String; + {-Convert a long integer to a string with Ch in comma positions.} + +function FloatFormL(const Mask : String ; R : TstFloat ; const LtCurr, + RtCurr : String ; Sep, DecPt : Char) : String; + {-Return a formatted string with digits from R merged into mask.} + +function LongIntFormL(const Mask : String ; L : LongInt ; const LtCurr, + RtCurr : String ; Sep : Char) : String; + {-Return a formatted string with digits from L merged into mask.} + +function StrChPosL(const P : String; C : Char; var Pos : Cardinal) : Boolean; + {-Return the position of a specified character within a string.} + +function StrStPosL(const P, S : String; var Pos : Cardinal) : Boolean; + {-Return the position of a specified substring within a string.} + +function StrStCopyL(const S : String; Pos, Count : Cardinal) : String; + {-Copy characters at a specified position in a string.} + +function StrChInsertL(const S : String; C : Char; Pos : Cardinal) : String; + {-Insert a character into a string at a specified position.} + +function StrStInsertL(const S1, S2 : String; Pos : Cardinal) : String; + {-Insert a string into another string at a specified position.} + +function StrChDeleteL(const S : String; Pos : Cardinal) : String; + {-Delete the character at a specified position in a string.} + +function StrStDeleteL(const S : String; Pos, Count : Cardinal) : String; + {-Delete characters at a specified position in a string.} + + +{-------------------------- New Functions -----------------------------------} + +function ContainsOnlyL(const S, Chars : String; + var BadPos : Cardinal) : Boolean; + +function ContainsOtherThanL(const S, Chars : String; + var BadPos : Cardinal) : Boolean; + +function CopyLeftL(const S : String; Len : Cardinal) : String; + {-Return the left Len characters of a string} + +function CopyMidL(const S : String; First, Len : Cardinal) : String; + {-Return the mid part of a string} + +function CopyRightL(const S : String; First : Cardinal) : String; + {-Return the right Len characters of a string} + +function CopyRightAbsL(const S : String; NumChars : Cardinal) : String; + {-Return NumChar characters starting from end} + +function CopyFromNthWordL(const S, WordDelims : String; + const AWord : String; N : Cardinal; {!!.02} + var SubString : String) : Boolean; + +function CopyFromToWordL(const S, WordDelims, Word1, Word2 : String; + N1, N2 : Cardinal; + var SubString : String) : Boolean; + +function CopyWithinL(const S, Delimiter : String; + Strip : Boolean) : String; + +function DeleteFromNthWordL(const S, WordDelims : String; + const AWord : String; N : Cardinal; {!!.02} + var SubString : String) : Boolean; + +function DeleteFromToWordL(const S, WordDelims, Word1, Word2 : String; + N1, N2 : Cardinal; + var SubString : String) : Boolean; + +function DeleteWithinL(const S, Delimiter : String) : String; + +function ExtractTokensL(const S, Delims: String; + QuoteChar : Char; + AllowNulls : Boolean; + Tokens : TStrings) : Cardinal; + +function IsChAlphaL(C : Char) : Boolean; + {-Returns true if Ch is an alpha} + +function IsChNumericL(C : Char; const Numbers : String) : Boolean; {!!.02} + {-Returns true if Ch in numeric set} + +function IsChAlphaNumericL(C : Char; const Numbers : String) : Boolean; {!!.02} + {-Returns true if Ch is an alpha or numeric} + +function IsStrAlphaL(const S : String) : Boolean; + {-Returns true if all characters in string are an alpha} + +function IsStrNumericL(const S, Numbers : String) : Boolean; + {-Returns true if all characters in string are in numeric set} + +function IsStrAlphaNumericL(const S, Numbers : String) : Boolean; + {-Returns true if all characters in string are alpha or numeric} + +function KeepCharsL(const S, Chars : String) : String; + +function LastWordL(const S, WordDelims, AWord : String; + var Position : Cardinal) : Boolean; + +function LastWordAbsL(const S, WordDelims : String; + var Position : Cardinal) : Boolean; + +function LastStringL(const S, AString : String; + var Position : Cardinal) : Boolean; + +function LeftTrimCharsL(const S, Chars : String) : String; + +function ReplaceWordL(const S, WordDelims, OldWord, NewWord : String; + N : Cardinal; + var Replacements : Cardinal) : String; + +function ReplaceWordAllL(const S, WordDelims, OldWord, NewWord : String; + var Replacements : Cardinal) : String; + +function ReplaceStringL(const S, OldString, NewString : String; + N : Cardinal; + var Replacements : Cardinal) : String; + +function ReplaceStringAllL(const S, OldString, NewString : String; + var Replacements : Cardinal) : String; + +function RepeatStringL(const RepeatString : String; + var Repetitions : Cardinal; + MaxLen : Cardinal) : String; + +function RightTrimCharsL(const S, Chars : String) : String; + +function StrWithinL(const S, SearchStr : string; + Start : Cardinal; + var Position : Cardinal) : boolean; + {-finds the position of a substring within a string starting at a given point} + +function TrimCharsL(const S, Chars : String) : String; + +function WordPosL(const S, WordDelims, AWord : String; + N : Cardinal; var Position : Cardinal) : Boolean; + {-returns the Occurrence instance of a word within a string} + + +implementation + + {-------- Numeric conversion -----------} + +function HexBL(B : Byte) : AnsiString; + {-Return the hex string for a byte.} +begin + SetLength(Result, 2); + Result[1] := StHexDigits[B shr 4]; + Result[2] := StHexDigits[B and $F]; +end; + +function HexWL(W : Word) : AnsiString; + {-Return the hex string for a word.} +begin + SetLength(Result, 4); + Result[1] := StHexDigits[hi(W) shr 4]; + Result[2] := StHexDigits[hi(W) and $F]; + Result[3] := StHexDigits[lo(W) shr 4]; + Result[4] := StHexDigits[lo(W) and $F]; +end; + +function HexLL(L : LongInt) : AnsiString; + {-Return the hex string for a long integer.} +begin + SetLength(Result, 8); + Result := HexWL(HiWord(DWORD(L))) + HexWL(LoWord(DWORD(L))); {!!.02} +end; + +function HexPtrL(P : Pointer) : AnsiString; + {-Return the hex string for a pointer.} +begin + SetLength(Result, 9); + Result := ':' + HexLL(LongInt(P)); +end; + +function BinaryBL(B : Byte) : AnsiString; + {-Return a binary string for a byte.} +var + I, N : Word; +begin + N := 1; + SetLength(Result, 8); + for I := 7 downto 0 do begin + Result[N] := StHexDigits[Ord(B and (1 shl I) <> 0)]; {0 or 1} + Inc(N); + end; +end; + +function BinaryWL(W : Word) : AnsiString; + {-Return the binary string for a word.} +var + I, N : Word; +begin + N := 1; + SetLength(Result, 16); + for I := 15 downto 0 do begin + Result[N] := StHexDigits[Ord(W and (1 shl I) <> 0)]; {0 or 1} + Inc(N); + end; +end; + +function BinaryLL(L : LongInt) : AnsiString; + {-Return the binary string for a long integer.} +var + I : Longint; + N : Byte; +begin + N := 1; + SetLength(Result, 32); + for I := 31 downto 0 do begin + Result[N] := StHexDigits[Ord(L and LongInt(1 shl I) <> 0)]; {0 or 1} + Inc(N); + end; +end; + +function OctalBL(B : Byte) : AnsiString; + {-Return an octal string for a byte.} +var + I : Word; +begin + SetLength(Result, 3); + for I := 0 to 2 do begin + Result[3-I] := StHexDigits[B and 7]; + B := B shr 3; + end; +end; + +function OctalWL(W : Word) : AnsiString; + {-Return an octal string for a word.} +var + I : Word; +begin + SetLength(Result, 6); + for I := 0 to 5 do begin + Result[6-I] := StHexDigits[W and 7]; + W := W shr 3; + end; +end; + +function OctalLL(L : LongInt) : AnsiString; + {-Return an octal string for a long integer.} +var + I : Word; +begin + SetLength(Result, 12); + for I := 0 to 11 do begin + Result[12-I] := StHexDigits[L and 7]; + L := L shr 3; + end; +end; + +function Str2Int16L(const S : AnsiString; var I : SmallInt) : Boolean; + {-Convert a string to an SmallInt.} + +var + ec : Integer; +begin + {note the automatic string conversion} + ValSmallint(S, I, ec); + if (ec = 0) then + Result := true + else begin + Result := false; + if (ec < 0) then + I := succ(length(S)) + else + I := ec; + end; +end; + +function Str2WordL(const S : AnsiString; var I : Word) : Boolean; + {-Convert a string to a word.} + +var + ec : Integer; +begin + {note the automatic string conversion} + ValWord(S, I, ec); + if (ec = 0) then + Result := true + else begin + Result := false; + if (ec < 0) then + I := succ(length(S)) + else + I := ec; + end; +end; + +function Str2LongL(const S : AnsiString; var I : LongInt) : Boolean; + {-Convert a string to a long integer.} + +var + ec : Integer; +begin + {note the automatic string conversion} + ValLongint(S, I, ec); + if (ec = 0) then + Result := true + else begin + Result := false; + if (ec < 0) then + I := succ(length(S)) + else + I := ec; + end; +end; + +{$IFDEF VER93} +function Str2RealL(const S : AnsiString; var R : Double) : Boolean; +{$ELSE} +function Str2RealL(const S : AnsiString; var R : Real) : Boolean; +{$ENDIF} + {-Convert a string to a real.} +var + Code : Integer; + St : AnsiString; +begin + Result := False; + if S = '' then Exit; + St := TrimTrailL(S); + if St = '' then Exit; + Val(ValPrepL(St), R, Code); + if Code <> 0 then begin + R := Code; + end else + Result := True; +end; + +function Str2ExtL(const S : AnsiString; var R : Extended) : Boolean; + {-Convert a string to an extended.} +var + Code : Integer; + P : AnsiString; +begin + Result := False; + if S = '' then Exit; + P := TrimTrailL(S); + if P = '' then Exit; + Val(ValPrepL(P), R, Code); + if Code <> 0 then begin + R := Code - 1; + end else + Result := True; +end; + +function Long2StrL(L : LongInt) : String; + {-Convert an integer type to a string.} +begin + Str(L, Result); +end; + +function Real2StrL(R : Double; Width : Byte; Places : ShortInt) : String; + {-Convert a real to a string.} +begin + Str(R:Width:Places, Result); +end; + +function Ext2StrL(R : Extended; Width : Byte; Places : ShortInt) : String; + {-Convert an extended to a string.} +begin + Str(R:Width:Places, Result); +end; + +function ValPrepL(const S : String) : String; + {-Prepares a string for calling Val.} +var + P : Cardinal; + C : Longint; +begin + Result := TrimSpacesL(S); + if Result <> '' then begin + if StrChPosL(Result, {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator, P) then begin + C := P; + Result[C] := '.'; + if C = Length(Result) then + SetLength(Result, Pred(C)); + end; + end else + Result := '0'; +end; + + {-------- General purpose string manipulation --------} + +function CharStrL(C : Char; Len : Cardinal) : String; + {-Return a string filled with the specified character.} +begin + Result := StringOfChar(C, Len) +end; + +function PadChL(const S : String; C : Char; Len : Cardinal) : String; + {-Pad a string on the right with a specified character.} +{$IFDEF UNICODE} +begin + Result := S; + if Length(Result) < Len then + Result := Result + StringOfChar(C, Len - Length(Result)); +end; +{$ELSE} +begin + if Length(S) >= LongInt(Len) then + Result := S + else begin + SetLength(Result, Len); + { copy current contents (if any) of S to Result } + if (Length(S) > 0) then {!!.01} + Move(S[1], Result[1], Length(S)); + + { add pad chars } + FillChar(Result[Succ(Length(S))], LongInt(Len)-Length(S), C); + end; +end; +{$ENDIF} + +function PadL(const S : String; Len : Cardinal) : String; + {-Pad a string on the right with spaces.} +begin + Result := PadChL(S, ' ', Len); +end; + +function LeftPadChL(const S : String; C : Char; Len : Cardinal) : String; + {-Pad a string on the left with a specified character.} +begin + {$IFDEF UNICODE} + if Length(S) > Len then + Result := S + else + Result := StringOfChar(C, Len - Length(S)) + S; + {$ELSE} + if Length(S) >= LongInt(Len) then + Result := S + else if Length(S) < MaxLongInt then begin + SetLength(Result, Len); + + { copy current contents (if any) of S to Result } + if (Length(S) > 0) then {!!.01} + Move(S[1], Result[Succ(Word(Len))-Length(S)], Length(S)); + + { add pad chars } + FillChar(Result[1], LongInt(Len)-Length(S), C); + end; + {$ENDIF} +end; + +function LeftPadL(const S : String; Len : Cardinal) : String; + {-Pad a string on the left with spaces.} +begin + Result := LeftPadChL(S, ' ', Len); +end; + +function TrimLeadL(const S : String) : String; + {-Return a string with leading white space removed} +begin + Result := TrimLeft(S); +end; + +function TrimTrailL(const S : String) : String; + {-Return a string with trailing white space removed.} +begin + Result := TrimRight(S); +end; + +function TrimL(const S : String) : String; + {-Return a string with leading and trailing white space removed.} +var + I : Longint; +begin + Result := S; + while (Length(Result) > 0) and (Result[Length(Result)] <= ' ') do + SetLength(Result, Pred(Length(Result))); + + I := 1; + while (I <= Length(Result)) and (Result[I] <= ' ') do + Inc(I); + Dec(I); + if I > 0 then + System.Delete(Result, 1, I); +end; + +function TrimSpacesL(const S : String) : String; + {-Return a string with leading and trailing spaces removed.} +var + I : Longint; +begin + Result := S; + while (Length(Result) > 0) and (Result[Length(Result)] = ' ') do + SetLength(Result, Pred(Length(Result))); + I := 1; + while (I <= Length(Result)) and (S[I] = ' ') do + Inc(I); + Dec(I); + if I > 0 then + System.Delete(Result, 1, I); +end; + +function CenterChL(const S : String; C : Char; Len : Cardinal) : String; + {-Pad a string on the left and right with a specified character.} +begin + if Length(S) >= LongInt(Len) then + Result := S + else if Length(S) < MaxLongInt then begin +// SetLength(Result, Len); +// FillChar(Result[1], Len, C); + Result := StringOfChar(C, Len); + if Length(S) > 0 then {!!.01} + Move(S[1], Result[Succ((LongInt(Len)-Length(S)) shr 1)], Length(S)*SizeOf(Char)); + end; +end; + +function CenterL(const S : String; Len : Cardinal) : String; + {-Pad a string on the left and right with spaces.} +begin + Result := CenterChL(S, ' ', Len); +end; + +function EntabL(const S : AnsiString; TabSize : Byte) : AnsiString; //TODO-UNICODE + {-Convert blanks in a string to tabs.} +var + InLen, OutLen : Cardinal; +begin + if S = '' then Exit; + InLen := Length(S); + OutLen := 0; + SetLength(Result, InLen); +asm + push ebx { Save registers } + push edi + push esi + + mov edi, [Result] + mov edi, [edi] + xor ecx, ecx + add cl, TabSize + jz @@Done + + mov esi, S + xor ebx, ebx { Zero EBX and EDX } + xor edx, edx + inc edx { Set output length to 1 } + +@@Next: + or ebx, ebx + je @@NoTab { Jump to NoTab if spacecount is zero } + mov eax, edx { IPos to EAX } + push edx + xor edx, edx + div ecx + cmp edx, 1 { Is mod = 1? } + pop edx + jne @@NoTab { If not, no tab } + + sub edi, ebx + sub OutLen, ebx + inc OutLen + xor ebx, ebx { Reset spacecount } + mov byte ptr [edi], 9h { Store a tab } + inc edi + +@@NoTab: + mov al, [esi] { Get next input character } + inc esi + cmp edx, InLen { End of string? } + jg @@Done { Yes, done } + inc ebx { Increment SpaceCount } + cmp al, 20h { Is character a space? } + jz @@Store { Yes, store it for now } + xor ebx, ebx { Reset SpaceCount } + cmp al, 27h { Is it a quote? } + jz @@Quotes { Yep, enter quote loop } + cmp al, 22h { Is it a doublequote? } + jnz @@Store { Nope, store it } + +@@Quotes: + mov ah, al { Save quote start } + +@@NextQ: + mov [edi], al { Store quoted character } + inc edi + inc OutLen + mov al, [esi] { Get next character } + inc esi + inc edx { Increment Ipos } + + cmp edx, ecx { At end of line? } + jae @@Store { If so, exit quote loop } + + cmp al, ah { Matching end quote? } + jnz @@NextQ { Nope, stay in quote loop } + + cmp al, 27h { Single quote? } + jz @@Store { Exit quote loop } + + cmp byte ptr [esi-2],'\' { Previous character an escape? } + jz @@NextQ { Stay in if so } + +@@Store: + mov [edi], al { Store last character } + inc edi + inc OutLen + inc edx { Increment input position } + jmp @@Next { Repeat while characters left } + +@@Done: + mov byte ptr [edi], 0h + pop esi + pop edi + pop ebx +end; + SetLength(Result, OutLen); +end; + +function DetabL(const S : AnsiString; TabSize : Byte) : AnsiString; //TODO-UNICODE + {-Expand tabs in a string to blanks.} +var + NumTabs : Integer; +begin + Result := ''; + if S = '' then Exit; + if TabSize = 0 then Exit; + Result := S; + NumTabs := CharCountL(S, #9); + if NumTabs = 0 then Exit; + SetLength(Result, Length(Result)+NumTabs*(Pred(TabSize))); +asm + push ebx { Save registers since we'll be changing them. } + push edi + push esi + + mov edi, Result { EDI => output string. } + mov esi, S { ESI => input string. } + xor ebx, ebx + mov bl, TabSize + mov edi, [edi] + xor ecx, ecx { Default input length = 0. } + xor edx, edx { Zero EDX for output length } + xor eax, eax { Zero EAX } + mov ecx, [esi-StrOffset].LStrRec.Length { Get input length. } + or ebx, ebx { TabSize = 0? } + jnz @@DefLength + mov ecx, edx { Return zero length string if TabSize = 0. } + +@@DefLength: + mov [edi-StrOffset].LStrRec.Length, ecx { Store default output length. } + or ecx, ecx + jz @@Done { Done if empty input string. } + +@@Next: + mov al, [esi] { Next input character. } + inc esi + cmp al, 09h { Is it a tab? } + jz @@Tab { Yes, compute next tab stop. } + mov [edi], al { No, store to output. } + inc edi + inc edx { Increment output length. } + dec ecx { Decrement input length. } + jnz @@Next + jmp @@StoreLen { Loop termination. } + +@@Tab: + push ecx { Save input length. } + push edx { Save output length. } + mov eax, edx { Get current output length in EDX:EAX. } + xor edx, edx + div ebx { Output length MOD TabSize in DX. } + mov ecx, ebx { Calc number of spaces to insert... } + sub ecx, edx { = TabSize - Mod value. } + pop edx + add edx, ecx { Add count of spaces into current output length. } + + mov eax,$2020 { Blank in AH, Blank in AL. } + shr ecx, 1 { Store blanks. } + rep stosw + adc ecx, ecx + rep stosb + pop ecx { Restore input length. } + dec ecx + jnz @@Next + {jmp @@Next} { Back for next input. } + +@@StoreLen: + xor ebx, ebx + mov [edi], bl { Store terminating null } + mov eax, edx + sub edi, eax + mov [edi-StrOffset].LStrRec.Length, edx { Store final length. } + +@@Done: + pop esi + pop edi + pop ebx +end; +end; + +function ScrambleL(const S, Key : AnsiString) : AnsiString; + {-Encrypt / Decrypt string with enhanced XOR encryption.} +var + I, J, LKey, LStr : Cardinal; +begin + Result := S; + if Key = '' then Exit; + if S = '' then Exit; + LKey := Length(Key); + LStr := Length(S); + I := 1; + J := LKey; + while I <= LStr do begin + if J = 0 then + J := LKey; + if (S[I] <> Key[J]) then + Result[I] := AnsiChar(Byte(S[I]) xor Byte(Key[J])); + Inc(I); + Dec(J); + end; +end; + +function SubstituteL(const S, FromStr, ToStr : String) : String; + {-Map the characters found in FromStr to the corresponding ones in ToStr.} +var + I : Cardinal; + P : Cardinal; +begin + Result := S; + if Length(FromStr) = Length(ToStr) then + for I := 1 to Length(Result) do begin + {P := System.Pos(S[I], FromStr);} + {if P <> 0 then} + if StrChPosL(FromStr, S[I], P) then + Result[I] := ToStr[P]; + end; +end; + +function FilterL(const S, Filters : String) : String; + {-Remove characters from a string. The characters to remove are specified in + ChSet.} +var + I : Cardinal; + Len : Cardinal; +begin + Len := 0; + SetLength(Result, Length(S)); + for I := 1 to Length(S) do + if not CharExistsL(Filters, S[I]) then begin + Inc(Len); + Result[Len] := S[I]; + end; + SetLength(Result, Len); +end; + + {--------------- Word / Char manipulation -------------------------} + +function CharExistsL(const S : String; C : Char) : Boolean; register; + {-Count the number of a given character in a string. } +{$IFDEF UNICODE} +var + I: Integer; +begin + Result := False; + for I := 1 to Length(S) do + begin + if S[I] = C then + begin + Result := True; + Break; + end; + end; +end; +{$ELSE} +asm + push ebx + xor ecx, ecx + or eax, eax + jz @@Done + mov ebx, [eax-StrOffset].LStrRec.Length + or ebx, ebx + jz @@Done + jmp @@5 + +@@Loop: + cmp dl, [eax+3] + jne @@1 + inc ecx + jmp @@Done + +@@1: + cmp dl, [eax+2] + jne @@2 + inc ecx + jmp @@Done + +@@2: + cmp dl, [eax+1] + jne @@3 + inc ecx + jmp @@Done + +@@3: + cmp dl, [eax+0] + jne @@4 + inc ecx + jmp @@Done + +@@4: + add eax, 4 + sub ebx, 4 + +@@5: + cmp ebx, 4 + jge @@Loop + + cmp ebx, 3 + je @@1 + + cmp ebx, 2 + je @@2 + + cmp ebx, 1 + je @@3 + +@@Done: + mov eax, ecx + pop ebx +end; +{$ENDIF} + +function CharCountL(const S : String; C : Char) : Cardinal; register; + {-Count the number of a given character in a string. } +{$IFDEF UNICODE} +var + I: Integer; +begin + Result := 0; + for I := 1 to Length(S) do + if S[I] = C then + Inc(Result); +end; +{$ELSE} +asm + push ebx + xor ecx, ecx + or eax, eax + jz @@Done + mov ebx, [eax-StrOffset].LStrRec.Length + or ebx, ebx + jz @@Done + jmp @@5 + +@@Loop: + cmp dl, [eax+3] + jne @@1 + inc ecx + +@@1: + cmp dl, [eax+2] + jne @@2 + inc ecx + +@@2: + cmp dl, [eax+1] + jne @@3 + inc ecx + +@@3: + cmp dl, [eax+0] + jne @@4 + inc ecx + +@@4: + add eax, 4 + sub ebx, 4 + +@@5: + cmp ebx, 4 + jge @@Loop + + cmp ebx, 3 + je @@1 + + cmp ebx, 2 + je @@2 + + cmp ebx, 1 + je @@3 + +@@Done: + mov eax, ecx + pop ebx +end; +{$ENDIF} + +function WordCountL(const S, WordDelims : String) : Cardinal; + {-Given an array of word delimiters, return the number of words in a string.} +var + I : Cardinal; + SLen : Cardinal; +begin + Result := 0; + I := 1; + SLen := Length(S); + + while I <= SLen do begin + {skip over delimiters} + while (I <= SLen) and CharExistsL(WordDelims, S[I]) do + Inc(I); + + {if we're not beyond end of S, we're at the start of a word} + if I <= SLen then + Inc(Result); + + {find the end of the current word} + while (I <= SLen) and not CharExistsL(WordDelims, S[I]) do + Inc(I); + end; +end; + +function WordPositionL(N : Cardinal; const S, WordDelims : String; + var Pos : Cardinal) : Boolean; + {-Given an array of word delimiters, set Pos to the start position of the + N'th word in a string. Result indicates success/failure.} +var + Count : Longint; + I : Longint; +begin + Count := 0; + I := 1; + Result := False; + + while (I <= Length(S)) and (Count <> LongInt(N)) do begin + {skip over delimiters} + while (I <= Length(S)) and CharExistsL(WordDelims, S[I]) do + Inc(I); + + {if we're not beyond end of S, we're at the start of a word} + if I <= Length(S) then + Inc(Count); + + {if not finished, find the end of the current word} + if Count <> LongInt(N) then + while (I <= Length(S)) and not CharExistsL(WordDelims, S[I]) do + Inc(I) + else begin + Pos := I; + Result := True; + end; + end; +end; + +function ExtractWordL(N : Cardinal; const S, WordDelims : String) : String; + {-Given an array of word delimiters, return the N'th word in a string.} +var + C : Cardinal; + I, J : Longint; +begin + Result := ''; + if WordPositionL(N, S, WordDelims, C) then begin + I := C; + {find the end of the current word} + J := I; + while (I <= Length(S)) and not + CharExistsL(WordDelims, S[I]) do + Inc(I); + SetLength(Result, I-J); + Move(S[J], Result[1], (I-J) * SizeOf(Char)); + end; +end; + + +function AsciiCountL(const S, WordDelims : String; Quote : Char) : Cardinal; + {-Return the number of words in a string.} +var + I : Longint; + InQuote : Boolean; +begin + Result := 0; + I := 1; + InQuote := False; + while I <= Length(S) do begin + {skip over delimiters} + while (I <= Length(S)) and (S[I] <> Quote) + and CharExistsL(WordDelims, S[I]) do + Inc(I); + {if we're not beyond end of S, we're at the start of a word} + if I <= Length(S) then + Inc(Result); + {find the end of the current word} + while (I <= Length(S)) and + (InQuote or not CharExistsL(WordDelims, S[I])) do begin + if S[I] = Quote then + InQuote := not InQuote; + Inc(I); + end; + end; +end; + +function AsciiPositionL(N : Cardinal; const S, WordDelims : String; + Quote : Char; var Pos : Cardinal) : Boolean; + {-Return the position of the N'th word in a string.} +var + Count, I : Longint; + InQuote : Boolean; +begin + Count := 0; + InQuote := False; + Result := False; + I := 1; + while (I <= Length(S)) and (Count <> LongInt(N)) do begin + {skip over delimiters} + while (I <= Length(S)) and (S[I] <> Quote) and + CharExistsL(WordDelims, S[I]) do + Inc(I); + {if we're not beyond end of S, we're at the start of a word} + if I <= Length(S) then + Inc(Count); + {if not finished, find the end of the current word} + if Count <> LongInt(N) then + while (I <= Length(S)) and (InQuote or not + CharExistsL(WordDelims, S[I])) do begin + if S[I] = Quote then + InQuote := not InQuote; + Inc(I); + end + else begin + Pos := I; + Result := True; + end; + end; +end; + +function ExtractAsciiL(N : Cardinal; const S, WordDelims : String; + Quote : Char) : String; + {-Given an array of word delimiters, return the N'th word in a string. Any + text within Quote characters is counted as one word.} +var + C : Cardinal; + I, J : Longint; + InQuote : Boolean; +begin + InQuote := False; + if AsciiPositionL(N, S, WordDelims, Quote, C) then begin + I := C; + J := I; + {find the end of the current word} + while (I <= Length(S)) and ((InQuote) + or not CharExistsL(WordDelims, S[I])) do begin + if S[I] = Quote then + InQuote := not(InQuote); + Inc(I); + end; + SetLength(Result, I-J); + Move(S[J], Result[1], I-J); + end; +end; + +procedure WordWrapL(const InSt : String; var OutSt, Overlap : String; + Margin : Cardinal; PadToMargin : Boolean); + {-Wrap a text string at a specified margin.} +var + InStLen : Cardinal; + EOS, BOS : Cardinal; + Len : Integer; {!!.02} +begin + InStLen := Length(InSt); + +{!!.02 - Added } + { handle empty string on input } + if InStLen = 0 then begin + OutSt := ''; + Overlap := ''; + Exit; + end; +{!!.02 - End Added } + + {find the end of the output string} + if InStLen > Margin then begin + {find the end of the word at the margin, if any} + EOS := Margin; + while (EOS <= InStLen) and (InSt[EOS] <> ' ') do + Inc(EOS); + if EOS > InStLen then + EOS := InStLen; + + {trim trailing blanks} + while (EOS > 0) and (InSt[EOS] = ' ') do {!!.04} + Dec(EOS); + + if EOS > Margin then begin + {look for the space before the current word} + while (EOS > 0) and (InSt[EOS] <> ' ') do + Dec(EOS); + + {if EOS = 0 then we can't wrap it} + if EOS = 0 then + EOS := Margin + else + {trim trailing blanks} + while (EOS > 0) and (InSt[EOS] = ' ') do {!!.04} + Dec(EOS); + end; + end else + EOS := InStLen; + + {copy the unwrapped portion of the line} + if EOS > 0 then begin {!!.04} + SetLength(OutSt, EOS); + Move(InSt[1], OutSt[1], Length(OutSt) * SizeOf(Char)); + end; {!!.04} + + {find the start of the next word in the line} + BOS := Succ(EOS); + while (BOS <= InStLen) and (InSt[BOS] = ' ') do + Inc(BOS); + + if BOS > InStLen then + SetLength(OverLap, 0) + else begin + {copy from the start of the next word to the end of the line} + + SetLength(OverLap, InStLen); + Move(InSt[BOS], Overlap[1], Succ(InStLen-BOS) * SizeOf(Char)); + SetLength(OverLap, Succ(InStLen-BOS)); + end; + + {pad the end of the output string if requested} +{!!.02 - Rewritten} + Len := Length(OutSt); + if PadToMargin and (Len < LongInt(Margin)) then begin +// SetLength(OutSt, Margin); +// FillChar(OutSt[Succ(Len)], LongInt(Margin)-Length(OutSt), ' '); + OutSt := OutSt + StringOfChar(' ', Margin - Length(OutSt)); + end; +{!!.02 - End Rewritten} +end; + + {--------------- String comparison and searching -----------------} +function CompStringL(const S1, S2 : String) : Integer; register; + {-Compare two strings.} +{$IFDEF FPC} +begin + Result := CompareStr(S1, S2); +end; +{$ELSE} +{$IFDEF UNICODE} +begin + Result := AnsiCompareStr(S1, S2); +end; +{$ELSE} +asm + push edi + mov edi, edx { EDI points to S2 } + push esi + mov esi, eax { ESI points to S1 } + + xor edx, edx + xor ecx, ecx + + or edi, edi + jz @@1 + mov edx, [edi-StrOffset].LStrRec.Length + +@@1: + or esi, esi + jz @@2 + mov ecx, [esi-StrOffset].LStrRec.Length + +@@2: + or eax, -1 { EAX holds temporary result } + + cmp ecx, edx { Compare lengths } + je @@EqLen { Lengths equal? } + jb @@Comp { Jump if S1 shorter than S1 } + + inc eax { S1 longer than S2 } + mov ecx, edx { Length(S2) in CL } + +@@EqLen: + inc eax { Equal or greater } + +@@Comp: + or ecx, ecx + jz @@Done { Done if either is empty } + + repe cmpsb { Compare until no match or ECX = 0 } + je @@Done { If Equal, result ready based on length } + + mov eax, 1 + ja @@Done { S1 Greater? Return 1 } + or eax, -1 { Else S1 Less, Return -1 } + +@@Done: + pop esi + pop edi +end; +{$ENDIF} +{$ENDIF} + +function CompUCStringL(const S1, S2 : String) : Integer; register; + {-Compare two strings. This compare is not case sensitive.} +{$IFDEF FPC} +begin + Result := Comparetext(S1, S2); +end; +{$ELSE} +{$IFDEF UNICODE} +begin + Result := AnsiCompareText(S1, S2); +end; +{$ELSE} +asm + push ebx { Save registers } + push edi + push esi + + mov edi, edx { EDI points to S2 } + mov esi, eax { ESI points to S1 } + + xor eax, eax + xor ecx, ecx + xor edx, edx { DL chars from S2 } + or ebx, -1 + + or edi, edi + jz @@1 + mov eax, [edi-StrOffset].LStrRec.Length + +@@1: + or esi, esi + jz @@2 + mov ecx, [esi-StrOffset].LStrRec.Length + +@@2: + cmp ecx, eax { Compare lengths } + je @@EqLen { Lengths equal? } + jb @@Comp { Jump if S1 shorter than S1 } + + inc ebx { S1 longer than S2 } + mov ecx, eax { Shorter length in ECX } + +@@EqLen: + inc ebx { Equal or greater } + +@@Comp: + or ecx, ecx + jz @@Done { Done if lesser string is empty } + +@@Start: + xor eax, eax { EAX holds chars from S1 } + mov al, [esi] { S1[?] into AL } + inc esi + + push ecx { Save registers } + push edx + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + + mov dl, [edi] { S2[?] into DL } + inc edi { Point EDI to next char in S2 } + mov dh, al + mov al, dl + mov dl, dh + + push ecx { Save registers } + push edx + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + + cmp dl, al { Compare until no match } + jne @@Output + dec ecx + jnz @@Start + + je @@Done { If Equal, result ready based on length } + +@@Output: + mov ebx, 1 + ja @@Done { S1 Greater? Return 1 } + or ebx, -1 { Else S1 Less, Return -1 } + +@@Done: + mov eax, ebx { Result into EAX } + pop esi { Restore Registers } + pop edi + pop ebx +end; +{$ENDIF} +{$ENDIF} + +function SoundexL(const S : AnsiString) : AnsiString; + {-Return 4 character soundex of an input string} +{$IFDEF FPC} +begin + Result := StrUtils.SoundEx(S); +end; +{$ELSE} +const + SoundexTable : array[0..255] of Char = + (#0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, + { A B C D E F G H I J K L M } + #0, '1', '2', '3', #0, '1', '2', #0, #0, '2', '2', '4', '5', + { N O P Q R S T U V W X Y X } + '5', #0, '1', '2', '6', '2', '3', #0, '1', #0, '2', #0, '2', + #0, #0, #0, #0, #0, #0, + { a b c d e f g h i j k l m } + #0, '1', '2', '3', #0, '1', '2', #0, #0, '2', '2', '4', '5', + { n o p q r s t u v w x y x } + '5', #0, '1', '2', '6', '2', '3', #0, '1', #0, '2', #0, '2', + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0); +begin + if S = '' then Exit; + SetLength(Result, 4); +asm + push edi + mov edi, [Result] { EDI => output string. } + mov edi, [edi] + push ebx + push esi + + mov esi, S { ESI => input string. } + mov dword ptr [edi], '0000' { Initialize output string to '0000'. } + xor eax, eax + mov [edi+4], al { Set null at end of string. } + + mov ecx, [esi-StrOffset].LStrRec.Length + or ecx, ecx { Exit if null string. } + jz @@Done + + mov al, [esi] { Get first character of input string. } + inc esi + + push ecx { Save ECX across call to CharUpper. } + push eax { Push Char onto stack for CharUpper. } + call CharUpper { Uppercase AL. } + pop ecx { Restore saved register. } + + mov [edi], al { Store first output character. } + inc edi + + dec ecx { One input character used. } + jz @@Done { Was input string one char long?. } + + mov bh, 03h { Output max 3 chars beyond first. } + mov edx, offset SoundexTable { EDX => Soundex table. } + xor eax, eax { Prepare for address calc. } + xor bl, bl { BL will be used to store 'previous char'. } + +@@Next: + mov al, [esi] { Get next char in AL. } + inc esi + mov al, [edx+eax] { Get soundex code into AL. } + or al, al { Is AL zero? } + jz @@NoStore { If yes, skip this char. } + cmp bl, al { Is it the same as the previous stored char? } + je @@NoStore { If yes, skip this char. } + mov [edi], al { Store char to Dest. } + inc edi + dec bh { Decrement output counter. } + jz @@Done { If zero, we're done. } + mov bl, al { New previous character. } + +@@NoStore: + dec ecx { Decrement input counter. } + jnz @@Next + +@@Done: + pop esi + pop ebx + pop edi +end; +end; +{$ENDIF} + +(* ---------------- deactivated for Lazarus + +function MakeLetterSetL(const S : AnsiString) : Longint; register; + {-Return a bit-mapped long storing the individual letters contained in S.} +asm + push ebx { Save registers } + push esi + + mov esi, eax { ESI => string } + xor ecx, ecx { Zero ECX } + xor edx, edx { Zero EDX } + {or edx, edx} + or eax, eax + jz @@Exit + xor eax, eax { Zero EAX } + add ecx, [esi-StrOffset].LStrRec.Length + jz @@Exit { Done if ECX is 0 } + +@@Next: + mov al, [esi] { EAX has next char in S } + inc esi + + push ecx { Save registers } + push edx + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + + sub eax, 'A' { Convert to bit number } + cmp eax, 'Z'-'A' { Was char in range 'A'..'Z'? } + ja @@Skip { Skip it if not } + + mov ebx, eax { Exchange EAX and ECX } + mov eax, ecx + mov ecx, ebx + ror edx, cl + or edx, 01h { Set appropriate bit } + rol edx, cl + mov ebx, eax { Exchange EAX and ECX } + mov eax, ecx + mov ecx, ebx + +@@Skip: + dec ecx + jnz @@Next { Get next character } + +@@Exit: + mov eax, edx { Move EDX to result } + pop esi { Restore registers } + pop ebx +end; + +{$IFDEF UNICODE} +procedure BMMakeTableL(const MatchString : UnicodeString; var BT : BTable); +begin + // Do nothing until BMSearchL is fixed +{var + I: Integer; + Len: Byte; +begin + Len := Length(MatchString); + if Len > 255 then + Len := 255; + + FillChar(BT, SizeOf(BT), Len); + for I := 1 to Length(MatchString) - 1 do + BT[Word(MatchString[I])] := Len - I; } +end; +{$ELSE} +procedure BMMakeTableL(const MatchString : AnsiString; var BT : BTable); register; + {-Build a Boyer-Moore link table} +asm + push edi { Save registers because they will be changed } + push esi + mov esi, eax { Move EAX to ESI } + push ebx + + or eax, eax + jz @@MTDone + + xor eax, eax { Zero EAX } + mov ecx, [esi-StrOffset].LStrRec.Length + cmp ecx, 0FFh { If ECX > 255, force to 255 } + jbe @@1 + mov ecx, 0FFh + +@@1: + mov ch, cl { Duplicate CL in CH } + mov eax, ecx { Fill each byte in EAX with length } + shl eax, 16 + mov ax, cx + mov edi, edx { Point to the table } + mov ecx, 64 { Fill table bytes with length } + rep stosd + cmp al, 1 { If length <= 1, we're done } + jbe @@MTDone + mov edi, edx { Reset EDI to beginning of table } + xor ebx, ebx { Zero EBX } + mov cl, al { Restore CL to length of string } + dec ecx + +@@MTNext: + mov al, [esi] { Load table with positions of letters } + mov bl, al { that exist in the search string } + inc esi + mov [edi+ebx], cl + dec cl + jnz @@MTNext + +@@MTDone: + pop ebx { Restore registers } + pop esi + pop edi +end; +{$ENDIF} + +{$IFDEF UNICODE} +function BMSearchL(var Buffer; BufLength: Cardinal; var BT: BTable; // TODO-UNICODE + const MatchString : String; out Pos : Cardinal) : Boolean; +var + BufPtr: PChar; +// s: string; +// Len: Integer; +// I,J,K: Integer; +begin + // the commented code doesn't work correctly, so use a simple Pos for now + BufPtr := PChar(@Buffer); + Pos := System.Pos(MatchString, BufPtr); + Exit(Pos <> 0); +end; +{$ELSE} +function BMSearchL(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : AnsiString; var Pos : Cardinal) : Boolean; register; + {-Use the Boyer-Moore search method to search a buffer for a string.} +var + BufPtr : Pointer; +asm + push edi { Save registers since we will be changing } + push esi + push ebx + + mov BufPtr, eax { Copy Buffer to local variable and ESI } + mov esi, MatchString { Set ESI to beginning of MatchString } + or esi, esi + jz @@BMSNotFound + mov edi, eax + mov ebx, ecx { Copy BT ptr to EBX } + mov ecx, edx { Length of buffer to ECX } + xor eax, eax { Zero EAX } + + mov edx, [esi-StrOffset].LStrRec.Length + cmp edx, 0FFh { If EDX > 255, force to 255 } + jbe @@1 + mov edx, 0FFh + +@@1: + cmp dl, 1 { Check to see if we have a trivial case } + ja @@BMSInit { If Length(MatchString) > 1 do BM search } + jb @@BMSNotFound { If Length(MatchString) = 0 we're done } + + mov al,[esi] { If Length(MatchString) = 1 do a REPNE SCASB } + mov ebx, edi + repne scasb + jne @@BMSNotFound { No match during REP SCASB } + mov esi, Pos { Set position in Pos } + {dec edi} { Found, calculate position } + sub edi, ebx + mov eax, 1 { Set result to True } + mov [esi], edi + jmp @@BMSDone { We're done } + +@@BMSInit: + dec edx { Set up for BM Search } + add esi, edx { Set ESI to end of MatchString } + add ecx, edi { Set ECX to end of buffer } + add edi, edx { Set EDI to first check point } + std { Backward string ops } + mov dh, [esi] { Set DH to character we'll be looking for } + dec esi { Dec ESI in prep for BMSFound loop } + jmp @@BMSComp { Jump to first comparison } + +@@BMSNext: + mov al, [ebx+eax] { Look up skip distance from table } + add edi, eax { Skip EDI ahead to next check point } + +@@BMSComp: + cmp edi, ecx { Have we reached end of buffer? } + jae @@BMSNotFound { If so, we're done } + mov al, [edi] { Move character from buffer into AL for comparison } + cmp dh, al { Compare } + jne @@BMSNext { If not equal, go to next checkpoint } + + push ecx { Save ECX } + dec edi + xor ecx, ecx { Zero ECX } + mov cl, dl { Move Length(MatchString) to ECX } + repe cmpsb { Compare MatchString to buffer } + je @@BMSFound { If equal, string is found } + + mov al, dl { Move Length(MatchString) to AL } + sub al, cl { Calculate offset that string didn't match } + add esi, eax { Move ESI back to end of MatchString } + add edi, eax { Move EDI to pre-string compare location } + inc edi + mov al, dh { Move character back to AL } + pop ecx { Restore ECX } + jmp @@BMSNext { Do another compare } + +@@BMSFound: { EDI points to start of match } + mov edx, BufPtr { Move pointer to buffer into EDX } + mov esi, Pos + sub edi, edx { Calculate position of match } + mov eax, edi + inc eax + inc eax + mov [esi], eax { Set Pos to position of match } + mov eax, 1 { Set result to True } + pop ecx { Restore ESP } + jmp @@BMSDone + +@@BMSNotFound: + xor eax, eax { Set result to False } + +@@BMSDone: + cld { Restore direction flag } + pop ebx { Restore registers } + pop esi + pop edi +end; +{$ENDIF} + +{$IFDEF UNICODE} +function BMSearchUCL(var Buffer; BufLength : Cardinal; var BT : BTable; // TODO-UNICODE + const MatchString : String ; var Pos : Cardinal) : Boolean; register; +var + BufPtr: PChar; +begin + BufPtr := PChar(@Buffer); + Pos := System.Pos(AnsiUpperCase(MatchString), AnsiUpperCase(BufPtr)); + Exit(Pos <> 0); +end; +{$ELSE} + +function BMSearchUCL(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : AnsiString ; var Pos : Cardinal) : Boolean; register; + {-Use the Boyer-Moore search method to search a buffer for a string. This + search is not case sensitive.} +var + BufPtr : Pointer; +asm + push edi { Save registers since we will be changing } + push esi + push ebx + + mov BufPtr, eax { Copy Buffer to local variable and ESI } + mov esi, MatchString { Set ESI to beginning of MatchString } + or esi, esi + jz @@BMSNotFound + mov edi, eax + mov ebx, ecx { Copy BT ptr to EBX } + mov ecx, edx { Length of buffer to ECX } + xor eax, eax { Zero EAX } + + mov edx, [esi-StrOffset].LStrRec.Length + cmp edx, 0FFh { If EDX > 255, force to 255 } + jbe @@1 + mov edx, 0FFh + +@@1: + or dl, dl { Check to see if we have a trivial case } + jz @@BMSNotFound { If Length(MatchString) = 0 we're done } + +@@BMSInit: + dec edx { Set up for BM Search } + add esi, edx { Set ESI to end of MatchString } + add ecx, edi { Set ECX to end of buffer } + add edi, edx { Set EDI to first check point } + mov dh, [esi] { Set DH to character we'll be looking for } + dec esi { Dec ESI in prep for BMSFound loop } + jmp @@BMSComp { Jump to first comparison } + +@@BMSNext: + mov al, [ebx+eax] { Look up skip distance from table } + add edi, eax { Skip EDI ahead to next check point } + +@@BMSComp: + cmp edi, ecx { Have we reached end of buffer? } + jae @@BMSNotFound { If so, we're done } + + push ebx { Save registers } + push ecx + push edx + mov al, [edi] { Move character from buffer into AL for comparison } + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + pop ebx + + cmp dh, al { Compare } + jne @@BMSNext { If not equal, go to next checkpoint } + + push ecx { Save ECX } + dec edi + xor ecx, ecx { Zero ECX } + mov cl, dl { Move Length(MatchString) to ECX } + jecxz @@BMSFound { If ECX is zero, string is found } + +@@StringComp: + xor eax, eax + mov al, [edi] { Get char from buffer } + dec edi { Dec buffer index } + + push ebx { Save registers } + push ecx + push edx + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + pop ebx + + mov ah, al { Move buffer char to AH } + mov al, [esi] { Get MatchString char } + dec esi + cmp ah, al { Compare } + loope @@StringComp { OK? Get next character } + je @@BMSFound { Matched! } + + xor ah, ah { Zero AH } + mov al, dl { Move Length(MatchString) to AL } + sub al, cl { Calculate offset that string didn't match } + add esi, eax { Move ESI back to end of MatchString } + add edi, eax { Move EDI to pre-string compare location } + inc edi + mov al, dh { Move character back to AL } + pop ecx { Restore ECX } + jmp @@BMSNext { Do another compare } + +@@BMSFound: { EDI points to start of match } + mov edx, BufPtr { Move pointer to buffer into EDX } + mov esi, Pos + sub edi, edx { Calculate position of match } + mov eax, edi + inc eax + inc eax + mov [esi], eax { Set Pos to position of match } + mov eax, 1 { Set result to True } + pop ecx { Restore ESP } + jmp @@BMSDone + +@@BMSNotFound: + xor eax, eax { Set result to False } + +@@BMSDone: + pop ebx { Restore registers } + pop esi + pop edi +end; +{$ENDIF} + +*) + {--------------- DOS pathname parsing -----------------} + +function DefaultExtensionL(const Name, Ext : String) : String; + {-Return a file name with a default extension attached.} +var + DotPos : Cardinal; +begin + if HasExtensionL(Name, DotPos) then + Result := Name + else if Name = '' then + Result := '' + else + Result := Name + '.' + Ext; +end; + +function ForceExtensionL(const Name, Ext : String) : String; + {-Force the specified extension onto the file name.} +var + DotPos : Cardinal; +begin + if HasExtensionL(Name, DotPos) then + Result := System.Copy(Name, 1, DotPos) + Ext + else if Name = '' then + Result := '' + else + Result := Name + '.' + Ext; +end; + +function JustFilenameL(const PathName : String) : String; + {-Return just the filename and extension of a pathname.} +var + I : Cardinal; +begin + Result := ''; + if PathName = '' then Exit; + I := Succ(Cardinal(Length(PathName))); + repeat + Dec(I); + until (I = 0) or (PathName[I] in DosDelimSet); {!!.01} + Result := System.Copy(PathName, Succ(I), StMaxFileLen); +end; + +function JustNameL(const PathName : String) : String; + {-Return just the filename (no extension, path, or drive) of a pathname.} +var + DotPos : Cardinal; + S : AnsiString; +begin + S := JustFileNameL(PathName); + if HasExtensionL(S, DotPos) then + S := System.Copy(S, 1, DotPos-1); + Result := S; +end; + +function JustExtensionL(const Name : String) : String; + {-Return just the extension of a pathname.} +var + DotPos : Cardinal; +begin + if HasExtensionL(Name, DotPos) then + Result := System.Copy(Name, Succ(DotPos), StMaxFileLen) + else + Result := ''; +end; + +function JustPathnameL(const PathName : String) : String; + {-Return just the drive and directory portion of a pathname.} +var + I : Cardinal; +begin + if PathName = '' then Exit; + + I := Succ(Cardinal(Length(PathName))); + repeat + Dec(I); + until (I = 0) or (PathName[I] in DosDelimSet); {!!.01} + + if I = 0 then + {Had no drive or directory name} + SetLength(Result, 0) + else if I = 1 then + {Either the root directory of default drive or invalid pathname} + Result := PathName[1] + else if (PathName[I] = '\') then begin + if PathName[Pred(I)] = ':' then + {Root directory of a drive, leave trailing backslash} + Result := System.Copy(PathName, 1, I) + else + {Subdirectory, remove the trailing backslash} + Result := System.Copy(PathName, 1, Pred(I)); + end else + {Either the default directory of a drive or invalid pathname} + Result := System.Copy(PathName, 1, I); +end; + +function AddBackSlashL(const DirName : String) : String; + {-Add a default backslash to a directory name} +begin + Result := DirName; + if (Length(Result) = 0) then + Exit; + if ((Length(Result) = 2) and (Result[2] = ':')) or + ((Length(Result) > 2) and (Result[Length(Result)] <> '\')) then + Result := Result + '\'; +end; + +function CleanFileNameL(const FileName : AnsiString) : AnsiString; + {-Return filename with at most 8 chars of name and 3 of extension} +var + DotPos : Cardinal; + NameLen : Word; +begin + if HasExtensionL(FileName, DotPos) then begin + {Take the first 8 chars of name and first 3 chars of extension} + NameLen := Pred(DotPos); + if NameLen > 8 then + NameLen := 8; + Result := System.Copy(FileName, 1, NameLen)+System.Copy(FileName, DotPos, 4); + end else + {Take the first 8 chars of name} + Result := System.Copy(FileName, 1, 8); +end; + +function CleanPathNameL(const PathName : String) : String; + {-Return a pathname cleaned up as DOS does it.} +var + I : Cardinal; + S : String; +begin + SetLength(Result, 0); + S := PathName; + + I := Succ(Cardinal(Length(S))); + repeat + dec(I); + if I > 2 then + if (S[I] = '\') and (S[I-1] = '\') then + if (S[I-2] <> ':') then + System.Delete(S, I, 1); + until I <= 0; + + I := Succ(Cardinal(Length(S))); + repeat + {Get the next directory or drive portion of pathname} + repeat + Dec(I); + until (I = 0) or (S[I] in DosDelimSet); {!!.02} + + {Clean it up and prepend it to output string} + Result := CleanFileNameL(System.Copy(S, Succ(I), StMaxFileLen)) + Result; + if I > 0 then begin + Result := S[I] + Result; + System.Delete(S, I, 255); + end; + until I <= 0; + +end; + +function HasExtensionL(const Name : String; var DotPos : Cardinal) : Boolean; + {-Determine if a pathname contains an extension and, if so, return the + position of the dot in front of the extension.} +var + I : Cardinal; +begin + DotPos := 0; + for I := Length(Name) downto 1 do + if (Name[I] = '.') and (DotPos = 0) then + DotPos := I; + Result := (DotPos > 0) + and not CharExistsL(System.Copy(Name, Succ(DotPos), StMaxFileLen), '\'); +end; + + {------------------ Formatting routines --------------------} + + +function CommaizeChL(L : Longint; Ch : Char) : String; + {-Convert a long integer to a string with Ch in comma positions} +var + Temp : string; + NumCommas, I, Len : Cardinal; + Neg : Boolean; +begin + SetLength(Temp, 1); + Temp[1] := Ch; + if L < 0 then begin + Neg := True; + L := Abs(L); + end else + Neg := False; + Result := Long2StrL(L); + Len := Length(Result); + NumCommas := (Pred(Len)) div 3; + for I := 1 to NumCommas do + System.Insert(Temp, Result, Succ(Len-(I * 3))); + if Neg then + System.Insert('-', Result, 1); +end; + +function CommaizeL(L : LongInt) : String; + {-Convert a long integer to a string with commas} +begin + Result := CommaizeChL(L, ','); +end; + +function FormPrimL(const Mask : String; R : TstFloat; const LtCurr, RtCurr : String; + Sep, DecPt : Char; AssumeDP : Boolean) : String; + {-Returns a formatted string with digits from R merged into the Mask} +const + Blank = 0; + Asterisk = 1; + Zero = 2; +const +{$IFOPT N+} + MaxPlaces = 18; +{$ELSE} + MaxPlaces = 11; +{$ENDIF} + FormChars : string = '#@*$-+,.'; + PlusArray : array[Boolean] of Char = ('+', '-'); + MinusArray : array[Boolean] of Char = (' ', '-'); + FillArray : array[Blank..Zero] of Char = (' ', '*', '0'); +var + S : string; {temporary string} + Filler : Integer; {char for unused digit slots: ' ', '*', '0'} + WontFit, {true if number won't fit in the mask} + AddMinus, {true if minus sign needs to be added} + Dollar, {true if floating dollar sign is desired} + Negative : Boolean; {true if B is negative} + StartF, {starting point of the numeric field} + EndF : Longint; {end of numeric field} + RtChars, {# of chars to add to right} + LtChars, {# of chars to add to left} + DotPos, {position of '.' in Mask} + Digits, {total # of digits} + Blanks, {# of blanks returned by Str} + Places, {# of digits after the '.'} + FirstDigit, {pos. of first digit returned by Str} + Extras, {# of extra digits needed for special cases} + DigitPtr : Byte; {pointer into temporary string of digits} + I : Cardinal; +label + EndFound, + RedoCase, + Done; +begin + {assume decimal point at end?} + Result := Mask; + if (not AssumeDP) and (not CharExistsL(Result, '.')) then + AssumeDP := true; + if AssumeDP and (Result <> '') then begin + SetLength(Result, Succ(Length(Result))); + Result[Length(Result)] := '.'; + end; + + RtChars := 0; + LtChars := 0; + + {check for empty string} + if Length(Result) = 0 then + goto Done; + + {initialize variables} + Filler := Blank; + DotPos := 0; + Places := 0; + Digits := 0; + Dollar := False; + AddMinus := True; + StartF := 1; + + {store the sign of the real and make it positive} + Negative := (R < 0); + R := Abs(R); + + {strip and count c's} + for I := Length(Result) downto 1 do begin + if Result[I] = 'C' then begin + Inc(RtChars); + System.Delete(Result, I, 1); + end else if Result[I] = 'c' then begin + Inc(LtChars); + System.Delete(Result, I, 1); + end; + end; + + {find the starting point for the field} + while (StartF <= Length(Result)) + {and (System.Pos(Result[StartF], FormChars) = 0) do} + and not CharExistsL(FormChars, Result[StartF]) do + Inc(StartF); + if StartF > Length(Result) then + goto Done; + + {find the end point for the field} + EndF := StartF; + for I := StartF to Length(Result) do begin + EndF := I; + case Result[EndF] of + '*' : Filler := Asterisk; + '@' : Filler := Zero; + '$' : Dollar := True; + '-', + '+' : AddMinus := False; + '#' : {ignore} ; + ',', + '.' : DotPos := EndF; + else + goto EndFound; + end; + {Inc(EndF);} + end; + + {if we get here at all, the last char was part of the field} + Inc(EndF); + +EndFound: + {if we jumped to here instead, it wasn't} + Dec(EndF); + + {disallow Dollar if Filler is Zero} + if Filler = Zero then + Dollar := False; + + {we need an extra slot if Dollar is True} + Extras := Ord(Dollar); + + {get total # of digits and # after the decimal point} + for I := StartF to EndF do + case Result[I] of + '#', '@', + '*', '$' : + begin + Inc(Digits); + if (I > DotPos) and (DotPos <> 0) then + Inc(Places); + end; + end; + + {need one more 'digit' if Places > 0} + Inc(Digits, Ord(Places > 0)); + + {also need an extra blank if (1) Negative is true, and (2) Filler is Blank, + and (3) AddMinus is true} + if Negative and AddMinus and (Filler = Blank) then + Inc(Extras) + else + AddMinus := False; + + {translate the real to a string} + Str(R:Digits:Places, S); + + {add zeros that Str may have left out} + if Places > MaxPlaces then begin + I := Length(S); +// SetLength(S, LongInt(I) + (Places-MaxPlaces)); +// FillChar(S[Succ(I)], Places-MaxPlaces, '0'); + S := StringOfChar('0', Places-MaxPlaces) + S; + while (Length(S) > Digits) and (S[1] = ' ') do + System.Delete(S, 1, 1); + end; + + {count number of initial blanks} + Blanks := 1; + while S[Blanks] = ' ' do + Inc(Blanks); + FirstDigit := Blanks; + Dec(Blanks); + + {the number won't fit if (a) S is longer than Digits or (b) the number of + initial blanks is less than Extras} + WontFit := (Length(S) > Digits) or (Blanks < Extras); + + {if it won't fit, fill decimal slots with '*'} + if WontFit then begin + for I := StartF to EndF do + case Result[I] of + '#', '@', '*', '$' : Result[I] := '*'; + '+' : Result[I] := PlusArray[Negative]; + '-' : Result[I] := MinusArray[Negative]; + end; + goto Done; + end; + + {fill initial blanks in S with Filler; insert floating dollar sign} + if Blanks > 0 then begin + //FillChar(S[1], Blanks, FillArray[Filler]); + Delete(S, 1, Blanks); + S := StringOfChar(FillArray[Filler], Blanks) + S; + + {put floating dollar sign in last blank slot if necessary} + if Dollar then begin + S[Blanks] := LtCurr[1]; + Dec(Blanks); + end; + + {insert a minus sign if necessary} + if AddMinus then + S[Blanks] := '-'; + end; + + {put in the digits / signs} + DigitPtr := Length(S); + for I := EndF downto StartF do begin +RedoCase: + case Result[I] of + '#', '@', '*', '$' : + if DigitPtr <> 0 then begin + Result[I] := S[DigitPtr]; + Dec(DigitPtr); + if (DigitPtr <> 0) and (S[DigitPtr] = '.') then {!!.01} + Dec(DigitPtr); + end + else + Result[I] := FillArray[Filler]; + ',' : + begin + Result[I] := Sep; + if (I < DotPos) and (DigitPtr < FirstDigit) then begin + Result[I] := '#'; + goto RedoCase; + end; + end; + '.' : + begin + Result[I] := DecPt; + if (I < DotPos) and (DigitPtr < FirstDigit) then begin + Result[I] := '#'; + goto RedoCase; + end; + end; + '+' : Result[I] := PlusArray[Negative]; + '-' : Result[I] := MinusArray[Negative]; + end; + end; + +Done: + if AssumeDP then + SetLength(Result, Pred(Length(Result))); + if RtChars > 0 then begin + S := RtCurr; + if Length(S) > RtChars then + SetLength(S, RtChars) + else + S := LeftPadL(S, RtChars); + Result := Result + S; + end; + if LtChars > 0 then begin + S := LtCurr; + if Length(S) > LtChars then + SetLength(S, LtChars) + else + S := PadL(S, LtChars); + Result := S + Result; + end; +end; + +function FloatFormL(const Mask : String ; R : TstFloat ; const LtCurr, + RtCurr : String ; Sep, DecPt : Char) : String; + {-Return a formatted string with digits from R merged into mask.} +begin + Result := FormPrimL(Mask, R, LtCurr, RtCurr, Sep, DecPt, False); +end; + +function LongIntFormL(const Mask : String ; L : LongInt ; const LtCurr, + RtCurr : String ; Sep : Char) : String; + {-Return a formatted string with digits from L merged into mask.} +begin + Result := FormPrimL(Mask, L, LtCurr, RtCurr, Sep, '.', True); +end; + +function StrChPosL(const P : String; C : Char; var Pos : Cardinal) : Boolean; + {-Return the position of a specified character within a string.} +{$IFDEF UNICODE} +begin + Pos := System.Pos(C, P); + Result := Pos <> 0; +end; +{$ELSE} +asm + push ebx { Save registers } + push edi + + or eax, eax { Protect against null string } + jz @@NotFound + + xor edi, edi { Zero counter } + mov ebx, [eax-StrOffset].LStrRec.Length { Get input length } + +@@Loop: + inc edi { Increment counter } + cmp [eax], dl { Did we find it? } + jz @@Found + inc eax { Increment pointer } + + cmp edi, ebx { End of string? } + jnz @@Loop { If not, loop } + +@@NotFound: + xor eax, eax { Not found, zero EAX for False } + mov [ecx], eax + jmp @@Done + +@@Found: + mov [ecx], edi { Set Pos } + mov eax, 1 { Set EAX to True } + +@@Done: + pop edi { Restore registers } + pop ebx +end; +{$ENDIF} + +function StrStPosL(const P, S : String; var Pos : Cardinal) : Boolean; + {-Return the position of a specified substring within a string.} +begin + Pos := System.Pos(S, P); + Result := Pos <> 0; +end; + +function StrStCopyL(const S : String; Pos, Count : Cardinal) : String; + {-Copy characters at a specified position in a string.} +begin + Result := System.Copy(S, Pos, Count); +end; + +function StrChInsertL(const S : String; C : Char; Pos : Cardinal) : String; +var + Temp : string; +begin + SetLength(Temp, 1); + Temp[1] := C; + Result := S; + System.Insert(Temp, Result, Pos); +end; + +function StrStInsertL(const S1, S2 : String; Pos : Cardinal) : String; + {-Insert a string into another string at a specified position.} +begin + Result := S1; + System.Insert(S2, Result, Pos); +end; + +function StrChDeleteL(const S : String; Pos : Cardinal) : String; + {-Delete the character at a specified position in a string.} +begin + Result := S; + System.Delete(Result, Pos, 1); +end; + +function StrStDeleteL(const S : String; Pos, Count : Cardinal) : String; + {-Delete characters at a specified position in a string.} +begin + Result := S; + System.Delete(Result, Pos, Count); +end; + + +{----------------------------------------------------------------------------} + +function CopyLeftL(const S : String; Len : Cardinal) : String; + {-Return the left Len characters of a string} +begin + if (Len < 1) or (S = '') then + Result := '' + else + Result := Copy(S, 1, Len); +end; + +{----------------------------------------------------------------------------} + +function CopyMidL(const S : String; First, Len : Cardinal) : String; + {-Return the mid part of a string} +begin + if (LongInt(First) > Length(S)) or (LongInt(Len) < 1) or (S = '') then + Result := '' + else + Result := Copy(S, First, Len); +end; + +{----------------------------------------------------------------------------} + +function CopyRightL(const S : String; First : Cardinal) : String; + {-Return the right Len characters of a string} +begin + if (LongInt(First) > Length(S)) or (First < 1) or (S = '') then + Result := '' + else + Result := Copy(S, First, Length(S)); +end; + +{----------------------------------------------------------------------------} + +function CopyRightAbsL(const S : String; NumChars : Cardinal) : String; + {-Return NumChar characters starting from end} +begin + if (Cardinal(Length(S)) > NumChars) then + Result := Copy(S, (Cardinal(Length(S)) - NumChars)+1, NumChars) + else + Result := S; +end; + +{----------------------------------------------------------------------------} + +function WordPosL(const S, WordDelims, AWord : String; + N : Cardinal; var Position : Cardinal) : Boolean; + {-returns the Nth instance of a given word within a string} +var + TmpStr : String; + Len, + I, + P1, + P2 : Cardinal; +begin + if (S = '') or (AWord = '') or (pos(AWord, S) = 0) or (N < 1) then begin + Result := False; + Position := 0; + Exit; + end; + + Result := False; + Position := 0; + + TmpStr := S; + I := 0; + Len := Length(AWord); + P1 := pos(AWord, TmpStr); + + while (P1 > 0) and (Length(TmpStr) > 0) do begin + P2 := P1 + pred(Len); + if (P1 = 1) then begin + if (pos(TmpStr[P2+1], WordDelims) > 0) then begin + Inc(I); + end else + System.Delete(TmpStr, 1, P2); + end else if (pos(TmpStr[P1-1], WordDelims) > 0) and +// ((pos(TmpStr[P2+1], WordDelims) > 0) or {!!.02} +// (LongInt(P2+1) = Length(TmpStr))) then begin {!!.02} + ((LongInt(P2+1) >= Length(TmpStr)) or {!!.02} + (pos(TmpStr[P2+1], WordDelims) > 0)) then begin {!!.02} + Inc(I); + end else if ((LongInt(P1 + pred(Len))) = Length(TmpStr)) then begin + if (P1 > 1) and (pos(TmpStr[P1-1], WordDelims) > 0) then + Inc(I); + end; + + if (I = N) then begin + Result := True; + Position := Position + P1; + Exit; + end; + System.Delete(TmpStr, 1, P2); + Position := Position + P2; + P1 := pos(AWord, TmpStr); + end; +end; + + +{----------------------------------------------------------------------------} + +function CopyFromNthWordL(const S, WordDelims : String; + const AWord : String; N : Cardinal; {!!.02} + var SubString : String) : Boolean; +var + P : Cardinal; +begin + if (WordPosL(S, WordDelims, AWord, N, P)) then begin + SubString := Copy(S, P, Length(S)); + Result := True; + end else begin + SubString := ''; + Result := False; + end; +end; + +{----------------------------------------------------------------------------} + +function DeleteFromNthWordL(const S, WordDelims : String; + const AWord : String; N : Cardinal; {!!.02} + var SubString : String) : Boolean; +var + P : Cardinal; +begin + SubString := S; + if (WordPosL(S, WordDelims, AWord, N, P)) then begin + Result := True; + SubString := Copy(S, 1, P-1); + end else begin + Result := False; + SubString := ''; + end; +end; + +{----------------------------------------------------------------------------} + +function CopyFromToWordL(const S, WordDelims, Word1, Word2 : String; + N1, N2 : Cardinal; + var SubString : String) : Boolean; +var + P1, + P2 : Cardinal; +begin + if (WordPosL(S, WordDelims, Word1, N1, P1)) then begin + if (WordPosL(S, WordDelims, Word2, N2, P2)) then begin + Dec(P2); + if (P2 > P1) then begin + Result := True; + SubString := Copy(S, P1, P2-P1); + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; +end; + +{----------------------------------------------------------------------------} + +function DeleteFromToWordL(const S, WordDelims, Word1, Word2 : String; + N1, N2 : Cardinal; + var SubString : String) : Boolean; +var + P1, + P2 : Cardinal; +begin + SubString := S; + if (WordPosL(S, WordDelims, Word1, N1, P1)) then begin + if (WordPosL(S, WordDelims, Word2, N2, P2)) then begin + Dec(P2); + if (P2 > P1) then begin + Result := True; + System.Delete(SubString, P1, P2-P1+1); + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; +end; + +{----------------------------------------------------------------------------} + +function CopyWithinL(const S, Delimiter : String; + Strip : Boolean) : String; +var + P1, + P2 : Cardinal; + TmpStr : String; +begin + if (S = '') or (Delimiter = '') or (pos(Delimiter, S) = 0) then + Result := '' + else begin + if (StrStPosL(S, Delimiter, P1)) then begin + TmpStr := Copy(S, LongInt(P1) + Length(Delimiter), Length(S)); + if StrStPosL(TmpStr, Delimiter, P2) then begin + Result := Copy(TmpStr, 1, P2-1); + if (not Strip) then + Result := Delimiter + Result + Delimiter; + end else begin + Result := TmpStr; + if (not Strip) then + Result := Delimiter + Result; + end; + end; + end; +end; + +{----------------------------------------------------------------------------} + +function DeleteWithinL(const S, Delimiter : String) : String; +var + P1, + P2 : Cardinal; + TmpStr : String; +begin + if (S = '') or (Delimiter = '') or (pos(Delimiter, S) = 0) then + Result := '' + else begin + if (StrStPosL(S, Delimiter, P1)) then begin + TmpStr := Copy(S, LongInt(P1) + Length(Delimiter), Length(S)); + if (pos(Delimiter, TmpStr) = 0) then + Result := Copy(S, 1, P1-1) + else begin + if (StrStPosL(TmpStr, Delimiter, P2)) then begin + Result := S; + P2 := LongInt(P2) + (2*Length(Delimiter)); + System.Delete(Result, P1, P2); + end; + end; + end; + end; +end; + +{----------------------------------------------------------------------------} + +function ReplaceWordL(const S, WordDelims, OldWord, NewWord : String; + N : Cardinal; + var Replacements : Cardinal) : String; +var + I, + C, + P1 : Cardinal; +begin + if (S = '') or (WordDelims = '') or (OldWord = '') or + (pos(OldWord, S) = 0) then begin + Result := S; + Replacements := 0; + Exit; + end; + + if (WordPosL(S, WordDelims, OldWord, N, P1)) then begin + Result := S; + System.Delete(Result, P1, Length(OldWord)); + + C := 0; + for I := 1 to Replacements do begin + if ((Length(NewWord)) + Length(Result)) < MaxLongInt then begin + Inc(C); + System.Insert(NewWord, Result, P1); + Inc(P1, Length(NewWord) + 1); + end else begin + Replacements := C; + Exit; + end; + end; + end else begin + Result := S; + Replacements := 0; + end; +end; + + +function ReplaceWordAllL(const S, WordDelims, OldWord, NewWord : String; + var Replacements : Cardinal) : String; +var + I, + C, + P1 : Cardinal; +begin + if (S = '') or (WordDelims = '') or (OldWord = '') or + (Pos(OldWord, S) = 0) then begin + Result := S; + Replacements := 0; + end else begin + Result := S; + C := 0; + while (WordPosL(Result, WordDelims, OldWord, 1, P1)) do begin + System.Delete(Result, P1, Length(OldWord)); + for I := 1 to Replacements do begin + if ((Length(NewWord) + Length(Result)) < MaxLongInt) then begin + Inc(C); + System.Insert(NewWord, Result, P1); + end else begin + Replacements := C; + Exit; + end; + end; + end; + Replacements := C; + end; +end; + + +{----------------------------------------------------------------------------} + +function ReplaceStringL(const S, OldString, NewString : String; + N : Cardinal; + var Replacements : Cardinal) : String; +var + I, + C, + P1 : Cardinal; + TmpStr : String; +begin + if (S = '') or (OldString = '') or (pos(OldString, S) = 0) then begin + Result := S; + Replacements := 0; + Exit; + end; + TmpStr := S; + + I := 1; + P1 := pos(OldString, TmpStr); + C := P1; + while (I < N) and (LongInt(C) < Length(TmpStr)) do begin + Inc(I); + System.Delete(TmpStr, 1, LongInt(P1) + Length(OldString)); + Inc(C, LongInt(P1) + Length(OldString)); + end; + Result := S; + System.Delete(Result, C, Length(OldString)); + + C := 0; + for I := 1 to Replacements do begin + if (((Length(NewString)) + Length(Result)) < MaxLongInt) then begin + Inc(C); + System.Insert(NewString, Result, P1); + Inc(P1, Length(NewString) + 1); + end else begin + Replacements := C; + Exit; + end; + end; +end; + + +function ReplaceStringAllL(const S, OldString, NewString : String; + var Replacements : Cardinal) : String; +var + I, + C : Cardinal; + P1 : longint; + Tmp: String; +begin + if (S = '') or (OldString = '') or (Pos(OldString, S) = 0) then + begin + Result := S; + Replacements := 0; + end + else begin + Tmp := S; + P1 := AnsiPos(OldString, S); + if (P1 > 0) then begin + Result := Copy(Tmp, 1, P1-1); + C := 0; + while (P1 > 0) do begin + for I := 1 to Replacements do begin + Inc(C); + Result := Result + NewString; + end; + Tmp := Copy(Tmp, P1+Length(OldString), MaxLongInt); + P1 := AnsiPos(OldString, Tmp); + if (P1 > 0) then begin + Result := Result + Copy(Tmp, 1, P1-1); + end else + Result := Result + Tmp; + end; + Replacements := C; + end else begin + Result := S; + Replacements := 0; + end; + end; +end; + + +function LastWordL(const S, WordDelims, AWord : String; + var Position : Cardinal) : Boolean; +var + TmpStr : String; + I : Cardinal; +begin + if (S = '') or (WordDelims = '') or + (AWord = '') or (pos(AWord, S) = 0) then begin + Result := False; + Position := 0; + Exit; + end; + + TmpStr := S; + I := Length(TmpStr); + while (pos(TmpStr[I], WordDelims) > 0) do begin + System.Delete(TmpStr, I, 1); + I := Length(TmpStr); + end; + + Position := Length(TmpStr); + repeat + while (pos(TmpStr[Position], WordDelims) = 0) and (Position > 1) do + Dec(Position); + if (Copy(TmpStr, Position + 1, Length(AWord)) = AWord) then begin + Inc(Position); + Result := True; + Exit; + end; + System.Delete(TmpStr, Position, Length(TmpStr)); + Position := Length(TmpStr); + until (Length(TmpStr) = 0); + Result := False; + Position := 0; +end; + + + +function LastWordAbsL(const S, WordDelims : String; + var Position : Cardinal) : Boolean; +begin + if (S = '') or (WordDelims = '') then begin + Result := False; + Position := 0; + Exit; + end; + +{find first non-delimiter character, if any. If not a "one-word wonder"} + Position := Length(S); + while (Position > 0) and (pos(S[Position], WordDelims) > 0) do + Dec(Position); + + if (Position = 0) then begin + Result := True; + Position := 1; + Exit; + end; + +{find next delimiter character} + while (Position > 0) and (pos(S[Position], WordDelims) = 0) do + Dec(Position); + Inc(Position); + Result := True; +end; + + + +function LastStringL(const S, AString : String; + var Position : Cardinal) : Boolean; +var + TmpStr : String; + I, C : Cardinal; +begin + if (S = '') or (AString = '') or (pos(AString, S) = 0) then begin + Result := False; + Position := 0; + Exit; + end; + + TmpStr := S; + C := 0; + I := pos(AString, TmpStr); + while (I > 0) do begin + Inc(C, LongInt(I) + Length(AString)); + System.Delete(TmpStr, 1, LongInt(I) + Length(AString)); + I := pos(AString, TmpStr); + end; +{Go back the length of AString since the while loop deletes the last instance} + Dec(C, Length(AString)); + Position := C; + Result := True; +end; + + + +function KeepCharsL(const S, Chars : String) : String; +var + FromInx : Cardinal; + ToInx : Cardinal; +begin + {if either the input string or the list of acceptable chars is empty + the destination string will also be empty} + if (S = '') or (Chars = '') then begin + Result := ''; + Exit; + end; + + {set the maximum length of the result string (it could be less than + this, of course} + SetLength(Result, length(S)); + + {start off the to index} + ToInx := 0; + + {in a loop, copy over the chars that match the list} + for FromInx := 1 to length(S) do + if CharExistsL(Chars, S[FromInx]) then begin + inc(ToInx); + Result[ToInx] := S[FromInx]; + end; + + {make sure that the length of the result string is correct} + SetLength(Result, ToInx); +end; + + + +function RepeatStringL(const RepeatString : String; + var Repetitions : Cardinal; + MaxLen : Cardinal) : String; +var + i : Cardinal; + Len : Cardinal; + ActualReps : Cardinal; +begin + Result := ''; + if (MaxLen <> 0) and + (Repetitions <> 0) and + (RepeatString <> '') then begin + Len := length(RepeatString); + ActualReps := MaxLen div Len; + if (ActualReps > Repetitions) then + ActualReps := Repetitions + else + Repetitions := ActualReps; + if (ActualReps > 0) then begin + SetLength(Result, ActualReps * Len); + for i := 0 to pred(ActualReps) do + Move(RepeatString[1], Result[i * Len + 1], Len * SizeOf(Char)); + end; + end; +end; + + + +function TrimCharsL(const S, Chars : String) : String; +begin + Result := RightTrimCharsL(S, Chars); + Result := LeftTrimCharsL(Result, Chars); +end; + + + +function RightTrimCharsL(const S, Chars : String) : String; +var + CutOff : integer; +begin + CutOff := length(S); + while (CutOff > 0) do begin + if not CharExistsL(Chars, S[CutOff]) then + Break; + dec(CutOff); + end; + if (CutOff = 0) then + Result := '' + else + Result := Copy(S, 1, CutOff); +end; + + + +function LeftTrimCharsL(const S, Chars : String) : String; +var + CutOff : integer; + LenS : integer; +begin + LenS := length(S); + CutOff := 1; + while (CutOff <= LenS) do begin + if not CharExistsL(Chars, S[CutOff]) then + Break; + inc(CutOff); + end; + if (CutOff > LenS) then + Result := '' + else + Result := Copy(S, CutOff, LenS - CutOff + 1); +end; + + + +function ExtractTokensL(const S, Delims: String; + QuoteChar : Char; + AllowNulls : Boolean; + Tokens : TStrings) : Cardinal; //overload; +var + State : (ScanStart, + ScanQuotedToken, + ScanQuotedTokenEnd, + ScanNormalToken, + ScanNormalTokenWithQuote); + CurChar : Char; + TokenStart : integer; + Inx : integer; +begin + {Notes: this routine implements the following state machine + start ----> ScanStart + ScanStart-----quote----->ScanQuotedToken + ScanStart-----delim----->ScanStart (1) + ScanStart-----other----->ScanNormalToken + ScanQuotedToken-----quote----->ScanQuotedTokenEnd + ScanQuotedToken-----other----->ScanQuotedToken + ScanQuotedTokenEnd-----quote----->ScanNormalTokenWithQuote + ScanQuotedTokenEnd-----delim----->ScanStart (2) + ScanQuotedTokenEnd-----other----->ScanNormalToken + ScanNormalToken-----quote----->ScanNormalTokenWithQuote + ScanNormalToken-----delim----->ScanStart (3) + ScanNormalToken-----other----->ScanNormalToken + ScanNormalTokenWithQuote-----quote----->ScanNormalTokenWithQuote + ScanNormalTokenWithQuote-----other----->ScanNormalToken + + (1) output a null token if allowed + (2) output a token, stripping quotes (if the dequoted token is + empty, output a null token if allowed) + (3) output a token; no quote stripping + + If the quote character is #0, it's taken to mean that the routine + should not check for quoted substrings.} + + {clear the tokens string list, set the return value to zero} + Tokens.Clear; + Result := 0; + + {if the input string is empty or the delimiter list is empty or + the quote character is found in the delimiter list, return zero + tokens found} + if (S = '') or + (Delims = '') or + CharExistsL(Delims, QuoteChar) then + Exit; + + {start off in the normal scanning state} + State := ScanStart; + + {the first token starts at position 1} + TokenStart := 1; + + {read through the entire string} + for Inx := 1 to length(S) do begin + + {get the current character} + CurChar := S[Inx]; + + {process the character according to the current state} + case State of + ScanStart : + begin + {if the current char is the quote character, switch states} + if (QuoteChar <> #0) and (CurChar = QuoteChar) then + State := ScanQuotedToken + + {if the current char is a delimiter, output a null token} + else if CharExistsL(Delims, CurChar) then begin + + {if allowed to, output a null token} + if AllowNulls then begin + Tokens.Add(''); + inc(Result); + end; + + {set the start of the next token to be one character after + this delimiter} + TokenStart := succ(Inx); + end + + {otherwise, the current char is starting a normal token, so + switch states} + else + State := ScanNormalToken + end; + + ScanQuotedToken : + begin + {if the current char is the quote character, switch states} + if (CurChar = QuoteChar) then + State := ScanQuotedTokenEnd + end; + + ScanQuotedTokenEnd : + begin + {if the current char is the quote character, we have a token + consisting of two (or more) quoted substrings, so switch + states} + if (CurChar = QuoteChar) then + State := ScanNormalTokenWithQuote + + {if the current char is a delimiter, output the token + without the quotes} + else if CharExistsL(Delims, CurChar) then begin + + {if the token is empty without the quotes, output a null + token only if allowed to} + if ((Inx - TokenStart) = 2) then begin + if AllowNulls then begin + Tokens.Add(''); + inc(Result); + end + end + + {else output the token without the quotes} + else begin + Tokens.Add(Copy(S, succ(TokenStart), Inx - TokenStart - 2)); + inc(Result); + end; + + {set the start of the next token to be one character after + this delimiter} + TokenStart := succ(Inx); + + {switch states back to the start state} + State := ScanStart; + end + + {otherwise it's a (complex) normal token, so switch states} + else + State := ScanNormalToken + end; + + ScanNormalToken : + begin + {if the current char is the quote character, we have a + complex token with at least one quoted substring, so switch + states} + if (QuoteChar <> #0) and (CurChar = QuoteChar) then + State := ScanNormalTokenWithQuote + + {if the current char is a delimiter, output the token} + else if CharExistsL(Delims, CurChar) then begin + Tokens.Add(Copy(S, TokenStart, Inx - TokenStart)); + inc(Result); + + {set the start of the next token to be one character after + this delimiter} + TokenStart := succ(Inx); + + {switch states back to the start state} + State := ScanStart; + end; + end; + + ScanNormalTokenWithQuote : + begin + {if the current char is the quote character, switch states + back to scanning a normal token} + if (CurChar = QuoteChar) then + State := ScanNormalToken; + end; + + end; + end; + + {we need to process the (possible) final token: first assume that + the current character index is just beyond the end of the string} + Inx := succ(length(S)); + + {if we are in the scanning quoted token state, we've read an opening + quote, but no closing one; increment the token start value} + if (State = ScanQuotedToken) then + inc(TokenStart) + + {if we've finished scanning a quoted token, we've read both quotes; + increment the token start value, and decrement the current index} + else if (State = ScanQuotedTokenEnd) then begin + inc(TokenStart); + dec(Inx); + end; + + {if the final token is not empty, output the token} + if (TokenStart < Inx) then begin + Tokens.Add(Copy(S, TokenStart, Inx - TokenStart)); + inc(Result); + end + {otherwise the final token is empty, so output a null token if + allowed to} + else if AllowNulls then begin + Tokens.Add(''); + inc(Result); + end; +end; + +function ContainsOnlyL(const S, Chars : String; + var BadPos : Cardinal) : Boolean; +var + I : Cardinal; +begin + if (S = '') then begin + Result := False; + BadPos := 0; + end else begin + for I := 1 to Length(S) do begin + if (not CharExistsL(Chars, S[I])) then begin + BadPos := I; + Result := False; + Exit; + end; + end; + Result := True; + BadPos := 0; + end; +end; + + + +function ContainsOtherThanL(const S, Chars : String; + var BadPos : Cardinal) : Boolean; +var + I : Cardinal; +begin + if (S = '') then begin + Result := False; + BadPos := 0; + end else begin + for I := 1 to Length(S) do begin + if (CharExistsL(Chars, S[I])) then begin + BadPos := I; + Result := True; + Exit; + end; + end; + Result := False; + BadPos := 0; + end; +end; + + + +function IsChAlphaL(C : Char) : Boolean; + {-Returns true if Ch is an alpha} +begin + {$IFDEF FPC} + Result := (C in ['a'..'z', 'A'..'Z']); + {$ELSE} + Result := Windows.IsCharAlpha(C); + {$ENDIF} +end; + + + +function IsChNumericL(C : Char; const Numbers : String) : Boolean; {!!.02} + {-Returns true if Ch in numeric set} +begin + Result := CharExistsL(Numbers, C); +end; + + + +function IsChAlphaNumericL(C : Char; const Numbers : String) : Boolean; {!!.02} + {-Returns true if Ch is an alpha or numeric} +begin + {$IFDEF FPC} + Result := IsChAlphaL(C) or CharExistsL(Numbers, C); + {$ELSE} + Result := Windows.IsCharAlpha(C) or CharExistsL(Numbers, C); + {$ENDIF} +end; + + + +function IsStrAlphaL(const S : String) : Boolean; + {-Returns true if all characters in string are an alpha} +var + I : Cardinal; +begin + Result := false; + if (length(S) > 0) then begin + for I := 1 to Length(S) do + {$IFDEF FPC} + if not IsChAlphaL(S[I]) then + {$ELSE} + if not Windows.IsCharAlpha(S[I]) then + {$ENDIF} + Exit; + Result := true; + end; +end; + + + +function IsStrNumericL(const S, Numbers : String) : Boolean; + {-Returns true if all characters in string are in numeric set} +var + i : Cardinal; +begin + Result := false; + if (length(S) > 0) then begin + for i := 1 to Length(S) do + if not CharExistsL(Numbers, S[i]) then + Exit; + Result := true; + end; +end; + + + +function IsStrAlphaNumericL(const S, Numbers : String) : Boolean; + {-Returns true if all characters in string are alpha or numeric} +var + i : Cardinal; +begin + Result := false; + if (length(S) > 0) then begin + for I := 1 to Length(S) do + {$IFDEF FPC} + if (not IsChAlphaL(S[i])) and + {$ELSE} + if (not Windows.IsCharAlpha(S[i])) and + {$ENDIF} + (not CharExistsL(Numbers, S[i])) then + Exit; + Result := true; + end; +end; + + +function StrWithinL(const S, SearchStr : string; + Start : Cardinal; + var Position : Cardinal) : boolean; +var + TmpStr : string; +begin + TmpStr := S; + if (Start > 1) then + System.Delete(TmpStr, 1, Start-1); + Position := pos(SearchStr, TmpStr); + if (Position > 0) then begin + Position := Position + Start - 1; + Result := True; + end else + Result := False; +end; + + +end. diff --git a/components/systools/source/run/ststrms.pas b/components/systools/source/run/ststrms.pas new file mode 100644 index 000000000..71190c2af --- /dev/null +++ b/components/systools/source/run/ststrms.pas @@ -0,0 +1,1424 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StStrms.pas 4.04 *} +{*********************************************************} +{* SysTools: Specialized Stream Classes for SysTools *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +{$I StDefine.inc} + +unit StStrms; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, + {$ELSE} + Windows, + {$ENDIF} + SysUtils, + Classes, + + StBase, + StConst; + +type + TStMemSize = Integer; + + TStBufferedStream = class(TStream) + private + FBufCount: TStMemSize; {count of valid bytes in buffer} + FBuffer : PAnsiChar; {buffer into underlying stream} + FBufOfs : longint; {offset of buffer in underlying stream} + FBufPos : TStMemSize; {current position in buffer} + FBufSize : TStMemSize; {size of buffer} + FDirty : boolean; {has data in buffer been changed?} + FSize : Int64; {size of underlying stream} + FStream : TStream; {underlying stream} + {$IFNDEF VERSION3} + FOnSetStreamSize : TStSetStreamSize; + {event to set underlying stream's size} + {$ENDIF} + protected + procedure bsSetStream(aValue : TStream); + + procedure bsInitForNewStream; virtual; + function bsReadChar(var aCh : AnsiChar) : boolean; + procedure bsReadFromStream; + procedure bsWriteToStream; + + {$IFDEF VERSION3} + procedure SetSize(NewSize : longint); override; + {$ENDIF} + public + constructor Create(aStream : TStream); + constructor CreateEmpty; + destructor Destroy; override; + + function Read(var Buffer; Count : longint) : longint; override; + function Seek(Offset : longint; Origin : word) : longint; override; + function Write(const Buffer; Count : longint) : longint; override; + {$IFNDEF VERSION3} + procedure SetSize(NewSize : longint); + {$ENDIF} + + property FastSize : Int64 read FSize; + property Stream : TStream read FStream write bsSetStream; + + {$IFNDEF VERSION3} + property OnSetStreamSize : TStSetStreamSize + read FOnSetStreamSize write FOnSetStreamSize; + {$ENDIF} + end; + +type +{!!.01 - moved to StBase.pas } +(* + TStLineTerminator = ( {possible line terminators...} + ltNone, {..no terminator, ie fixed length lines} + ltCR, {..carriage return (#13)} + ltLF, {..line feed (#10)} + ltCRLF, {..carriage return/line feed (#13/#10)} + ltOther); {..another character} +*) +{!!.01 - end moved } + + + // TODO-UNICODE: add TStUnicodeTextStream + + TStAnsiTextStream = class(TStBufferedStream) + private + FLineEndCh : AnsiChar; + FLineLen : integer; + FLineTerm : TStLineTerminator; + FFixedLine : PAnsiChar; + FLineCount : longint; + FLineCurrent : longint; + FLineCurOfs : longint; + FLineIndex : TList; + FLineInxStep : longint; + FLineInxTop : integer; + protected + function atsGetLineCount : longint; + + procedure atsSetLineTerm(aValue : TStLineTerminator); + procedure atsSetLineEndCh(aValue : AnsiChar); + procedure atsSetLineLen(aValue : integer); + + procedure atsGetLine(var aStartPos : longint; + var aEndPos : longint; + var aLen : longint); + procedure atsResetLineIndex; + + procedure bsInitForNewStream; override; + public + constructor Create(aStream : TStream); + destructor Destroy; override; + + function AtEndOfStream : boolean; + + function ReadLine : AnsiString; + function ReadLineArray(aCharArray : PAnsiChar; aLen : TStMemSize) + : TStMemSize; + function ReadLineZ(aSt : PAnsiChar; aMaxLen : TStMemSize) : PAnsiChar; + + function SeekNearestLine(aOffset : longint) : longint; + function SeekLine(aLineNum : longint) : longint; + + procedure WriteLine(const aSt : AnsiString); + procedure WriteLineArray(aCharArray : PAnsiChar; aLen : TStMemSize); + procedure WriteLineZ(aSt : PAnsiChar); + + property FixedLineLength : integer + read FLineLen write atsSetLineLen; + property LineCount : longint + read atsGetLineCount; + property LineTermChar : AnsiChar + read FLineEndCh write atsSetLineEndCh; + property LineTerminator : TStLineTerminator + read FLineTerm write atsSetLineTerm; + end; + + {$IFNDEF FPC} + TStMemoryMappedFile = class(TStream) + protected {private} + FBuffer : Pointer; + FHeaderSize : Word; + FDataSize : Cardinal; + FHandle : THandle; + FMapObj : THandle; + FMaxHi : Cardinal; + FMaxLo : Cardinal; + FMutex : THandle; + FPos : Cardinal; + FReadOnly : Boolean; + FSharedData : Boolean; + + protected + function GetDataSize : Cardinal; + + public + constructor Create(const FileName : string; {!!.02} + MaxSize : Cardinal; + ReadOnly : Boolean; + SharedData : Boolean); + destructor Destroy; override; + + function Read(var Buffer; Count : Longint) : Longint; override; + function Seek(Offset : Longint; Origin : Word) : Longint; override; + function Write(const Buffer; Count : Longint) : Longint; override; + + property DataSize : Cardinal + read GetDataSize; + + property MaxSize : Cardinal + read FMaxLo; + + property Position : Cardinal + read FPos; + + property ReadOnly : Boolean + read FReadOnly; + + property SharedData : Boolean + read FSharedData; + end; + {$ENDIF} + +implementation + +const + LineTerm : array [TStLineTerminator] of + array [0..1] of AnsiChar = + ('', #13, #10, #13#10, ''); + +const + LineIndexCount = 1024; + LineIndexMax = pred(LineIndexCount); + + +{--- Helper routines ---------------------------------------------------------} + +function MinLong(A, B : longint) : longint; +begin + if A < B then + Result := A + else + Result := B; +end; + + +{-----------------------------------------------------------------------------} +{ TStBufferedStream } +{-----------------------------------------------------------------------------} + +constructor TStBufferedStream.Create(aStream : TStream); +begin + inherited Create; + + {allocate the buffer} + FBufSize := 4096; + GetMem(FBuffer, FBufSize); + + {save the stream} + if (aStream = nil) then + RaiseStError(EStBufStreamError, stscNilStream); + FStream := aStream; + + bsInitForNewStream; +end; + +{-----------------------------------------------------------------------------} + +constructor TStBufferedStream.CreateEmpty; +begin + inherited Create; + + {allocate the buffer} + FBufSize := 4096; + GetMem(FBuffer, FBufSize); + + bsInitForNewStream +end; + +{-----------------------------------------------------------------------------} + +destructor TStBufferedStream.Destroy; +begin + if (FBuffer <> nil) then begin + if FDirty and (FStream <> nil) then + bsWriteToStream; + FreeMem(FBuffer, FBufSize); + end; + + inherited Destroy; +end; + +{-----------------------------------------------------------------------------} + +procedure TStBufferedStream.bsInitForNewStream; +begin + if (FStream <> nil) then + FSize := FStream.Size + else + FSize := 0; + FBufCount := 0; + FBufOfs := 0; + FBufPos := 0; + FDirty := false; +end; + +{-----------------------------------------------------------------------------} + +function TStBufferedStream.bsReadChar(var aCh : AnsiChar) : boolean; +begin + {is there anything to read?} + if (FSize = (FBufOfs + FBufPos)) then begin + Result := false; + Exit; + end; + {if we get here, we'll definitely read a character} + Result := true; + {make sure that the buffer has some data in it} + if (FBufCount = 0) then + bsReadFromStream + else if (FBufPos = FBufCount) then begin + if FDirty then + bsWriteToStream; + FBufPos := 0; + inc(FBufOfs, FBufSize); + bsReadFromStream; + end; + {get the next character} + aCh := AnsiChar(FBuffer[FBufPos]); + inc(FBufPos); +end; + +{-----------------------------------------------------------------------------} + +procedure TStBufferedStream.bsReadFromStream; +var + NewPos : longint; +begin + {assumptions: FBufOfs is where to read the buffer + FBufSize is the number of bytes to read + FBufCount will be the number of bytes read} + NewPos := FStream.Seek(FBufOfs, soFromBeginning); + if (NewPos <> FBufOfs) then + RaiseStError(EStBufStreamError, stscNoSeekForRead); + FBufCount := FStream.Read(FBuffer^, FBufSize); +end; + +{-----------------------------------------------------------------------------} + +procedure TStBufferedStream.bsSetStream(aValue : TStream); +begin + if (aValue <> FStream) then begin + {if the buffer is dirty, flush it to the current stream} + if FDirty and (FStream <> nil) then + bsWriteToStream; + {remember the stream and initialize all fields} + FStream := aValue; + bsInitForNewStream; + end; +end; + +{-----------------------------------------------------------------------------} + +procedure TStBufferedStream.bsWriteToStream; +var + NewPos : longint; + BytesWritten : longint; +begin + {assumptions: FDirty is true + FBufOfs is where to write the buffer + FBufCount is the number of bytes to write + FDirty will be set false afterwards} + NewPos := FStream.Seek(FBufOfs, soFromBeginning); + if (NewPos <> FBufOfs) then + RaiseStError(EStBufStreamError, stscNoSeekForWrite); + BytesWritten := FStream.Write(FBuffer^, FBufCount); + if (BytesWritten <> FBufCount) then + RaiseStError(EStBufStreamError, stscCannotWrite); + FDirty := false; +end; + +{-----------------------------------------------------------------------------} + +function TStBufferedStream.Read(var Buffer; Count : longint) : longint; +var + BytesToGo : longint; + BytesToRead : longint; +// BufAsBytes : TByteArray absolute Buffer; {!!.02} +// DestPos : longint; {!!.02} + BufAsBytes : PByte; {!!.02} +begin + BufAsBytes := @Buffer; {!!.02} + + if (FStream = nil) then + RaiseStError(EStBufStreamError, stscNilStream); + {calculate the number of bytes we could read if possible} + BytesToGo := MinLong(Count, FSize - (FBufOfs + FBufPos)); + {we will return this number of bytes or raise an exception} + Result := BytesToGo; + {are we going to read some data after all?} + if (BytesToGo > 0) then begin + {make sure that the buffer has some data in it} + if (FBufCount = 0) then + bsReadFromStream; + {read as much as we can from the current buffer} + BytesToRead := MinLong(BytesToGo, FBufCount - FBufPos); + {transfer that number of bytes} +// Move(FBuffer[FBufPos], BufAsBytes[0], BytesToRead); {!!.02} + Move(FBuffer[FBufPos], BufAsBytes^, BytesToRead); {!!.02} + {update our counters} + inc(FBufPos, BytesToRead); + dec(BytesToGo, BytesToRead); + {if we have more bytes to read then we've reached the end of the + buffer and so we need to read another, and another, etc} +// DestPos := 0; {!!.02} + while BytesToGo > 0 do begin + {if the current buffer is dirty, write it out} + if FDirty then + bsWriteToStream; + {position and read the next buffer} + FBufPos := 0; + inc(FBufOfs, FBufSize); + bsReadFromStream; + {calculate the new destination position, and the number of bytes + to read from this buffer} +// inc(DestPos, BytesToRead); {!!.02} + Inc(BufAsBytes, BytesToRead); {!!.02} + BytesToRead := MinLong(BytesToGo, FBufCount - FBufPos); + {transfer that number of bytes} +// Move(FBuffer[FBufPos], BufAsBytes[DestPos], BytesToRead); {!!.02} + Move(FBuffer[FBufPos], BufAsBytes^, BytesToRead); {!!.02} + + {update our counters} + inc(FBufPos, BytesToRead); + dec(BytesToGo, BytesToRead); + end; + end; +end; + +{-----------------------------------------------------------------------------} + +function TStBufferedStream.Seek(Offset : longint; Origin : word) : longint; +var + NewPos : longint; + NewOfs : longint; +begin + if (FStream = nil) then + RaiseStError(EStBufStreamError, stscNilStream); + {optimization: to help code that just wants the current stream + position (ie, reading the Position property), check for this as a + special case} + if (Offset = 0) and (Origin = soFromCurrent) then begin + Result := FBufOfs + FBufPos; + Exit; + end; + {calculate the desired position} + case Origin of + soFromBeginning : NewPos := Offset; + soFromCurrent : NewPos := (FBufOfs + FBufPos) + Offset; + soFromEnd : NewPos := FSize + Offset; + else + RaiseStError(EStBufStreamError, stscBadOrigin); + NewPos := 0; {to fool the compiler's warning--we never get here} + end; + {force the new position to be valid} + if (NewPos < 0) then + NewPos := 0 + else if (NewPos > FSize) then + NewPos := FSize; + {calculate the offset for the buffer} + NewOfs := (NewPos div FBufSize) * FBufSize; + {if the offset differs, we have to move the buffer window} + if (NewOfs <> FBufOfs) then begin + {check to see whether we have to write the current buffer to the + original stream first} + if FDirty then + bsWriteToStream; + {mark the buffer as empty} + FBufOfs := NewOfs; + FBufCount := 0; + end; + {set the position within the buffer} + FBufPos := NewPos - FBufOfs; + Result := NewPos; +end; + +{-----------------------------------------------------------------------------} + +procedure TStBufferedStream.SetSize(NewSize : longint); +var + NewPos : longint; +begin + {get rid of the simple case first where the new size and the old + size are the same} + if (NewSize = FSize) then + Exit; + {if the buffer is dirty, write it out} + if FDirty then + bsWriteToStream; + {now set the size of the underlying stream} + FStream.Size := NewSize; + {patch up the buffer fields so that the buffered stream points to + somewhere in the newly resized stream} + NewPos := FBufOfs + FBufPos; + if (NewPos > NewSize) then + NewPos := NewSize; + bsInitForNewStream; + Seek(NewPos, soFromBeginning); +end; + +{-----------------------------------------------------------------------------} + +function TStBufferedStream.Write(const Buffer; Count : longint) : longint; +var + BytesToGo : longint; + BytesToWrite: longint; +// BufAsBytes : TByteArray absolute Buffer; {!!.02} +// DestPos : longint; {!!.02} + BufAsBytes : PByte; {!!.02} +begin + BufAsBytes := @Buffer; {!!.02} + + if (FStream = nil) then + RaiseStError(EStBufStreamError, stscNilStream); + {calculate the number of bytes we should be able to write} + BytesToGo := Count; + {we will return this number of bytes or raise an exception} + Result := BytesToGo; + {are we going to write some data?} + if (BytesToGo > 0) then begin + {try and make sure that the buffer has some data in it} + if (FBufCount = 0) then + bsReadFromStream; + {write as much as we can to the current buffer} + BytesToWrite := MinLong(BytesToGo, FBufSize - FBufPos); + {transfer that number of bytes} +// Move(BufAsBytes[0], FBuffer[FBufPos], BytesToWrite); {!!.02} + Move(BufAsBytes^, FBuffer[FBufPos], BytesToWrite); {!!.02} + FDirty := true; + {update our counters} + inc(FBufPos, BytesToWrite); + if (FBufCount < FBufPos) then begin + FBufCount := FBufPos; + FSize := FBufOfs + FBufPos; + end; + dec(BytesToGo, BytesToWrite); + {if we have more bytes to write then we've reached the end of the + buffer and so we need to write another, and another, etc} +// DestPos := 0; {!!.02} + while BytesToGo > 0 do begin + {as the current buffer is dirty, write it out} + bsWriteToStream; + {position and read the next buffer, if required} + FBufPos := 0; + inc(FBufOfs, FBufSize); + if (FBufOfs < FSize) then + bsReadFromStream + else + FBufCount := 0; + {calculate the new destination position, and the number of bytes + to write to this buffer} +// inc(DestPos, BytesToWrite); {!!.02} + Inc(BufAsBytes, BytesToWrite); {!!.02} + BytesToWrite := MinLong(BytesToGo, FBufSize - FBufPos); + {transfer that number of bytes} +// Move(BufAsBytes[DestPos], FBuffer[0], BytesToWrite); {!!.02} + Move(BufAsBytes^, FBuffer[0], BytesToWrite); {!!.02} + FDirty := true; + {update our counters} + inc(FBufPos, BytesToWrite); + if (FBufCount < FBufPos) then begin + FBufCount := FBufPos; + FSize := FBufOfs + FBufPos; + end; + dec(BytesToGo, BytesToWrite); + end; + end; +end; + +{-----------------------------------------------------------------------------} +{ TStAnsiTextStream } +{-----------------------------------------------------------------------------} + +constructor TStAnsiTextStream.Create(aStream : TStream); +begin + inherited Create(aStream); + + {set up the line index variables} + atsResetLineIndex; +end; + +{-----------------------------------------------------------------------------} + +destructor TStAnsiTextStream.Destroy; +begin + {if needed, free the fixed line buffer} + if (FFixedLine <> nil) then + FreeMem(FFixedLine, FixedLineLength); + {free the line index} + FLineIndex.Free; + inherited Destroy; +end; + +{-----------------------------------------------------------------------------} + +function TStAnsiTextStream.AtEndOfStream : boolean; +begin + Result := FSize = (FBufOfs + FBufPos); +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.atsGetLine(var aStartPos : longint; + var aEndPos : longint; + var aLen : longint); +var + Done : boolean; + Ch : AnsiChar; + PrevCh : AnsiChar; +begin + if (LineTerminator = ltNone) then begin + aStartPos := FBufOfs + FBufPos; + aEndPos := Seek(aStartPos + FixedLineLength, soFromBeginning); + aLen := aEndPos - aStartPos; + end + else begin + aStartPos := FBufOfs + FBufPos; + Ch := #0; + Done := false; + while not Done do begin + PrevCh := Ch; + if not bsReadChar(Ch) then begin + Done := true; + aEndPos := FBufOfs + FBufPos; + aLen := aEndPos - aStartPos; + end + else begin + case LineTerminator of + ltNone : {this'll never get hit}; + ltCR : if (Ch = #13) then begin + Done := true; + aEndPos := FBufOfs + FBufPos; + aLen := aEndPos - aStartPos - 1; + end; + ltLF : if (Ch = #10) then begin + Done := true; + aEndPos := FBufOfs + FBufPos; + aLen := aEndPos - aStartPos - 1; + end; + ltCRLF : if (Ch = #10) then begin + Done := true; + aEndPos := FBufOfs + FBufPos; + if PrevCh = #13 then + aLen := aEndPos - aStartPos - 2 + else + aLen := aEndPos - aStartPos - 1; + end; + ltOther: if (Ch = LineTermChar) then begin + Done := true; + aEndPos := FBufOfs + FBufPos; + aLen := aEndPos - aStartPos - 1; + end; + else + RaiseStError(EStBufStreamError, stscBadTerminator); + end; + end; + end; + end; +end; + +{-----------------------------------------------------------------------------} + +function TStAnsiTextStream.atsGetLineCount : longint; +begin + if FLineCount < 0 then + Result := MaxLongInt + else + Result := FLineCount; +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.atsResetLineIndex; +begin + {make sure we have a line index} + if (FLineIndex = nil) then begin + FLineIndex := TList.Create; {create the index: even elements are} + FLineIndex.Count := LineIndexCount * 2; {linenums, odd are offsets} + + {if we didn't have a line index, set up some reasonable defaults} + FLineTerm := ltCRLF; {normal Windows text file terminator} + FLineEndCh := #10; {not used straight away} + FLineLen := 80; {not used straight away} + end; + FLineIndex[0] := pointer(0); {the first line is line 0 and...} + FLineIndex[1] := pointer(0); {...it starts at position 0} + FLineInxTop := 0; {the top valid index} + FLineInxStep := 1; {step count before add a line to index} + FLineCount := -1; {number of lines (-1 = don't know)} + FLineCurrent := 0; {current line} + FLineCurOfs := 0; {current line offset} +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.atsSetLineTerm(aValue : TStLineTerminator); +begin + if (aValue <> LineTerminator) and ((FBufOfs + FBufPos) = 0) then begin + {if there was no terminator, free the line buffer} + if (LineTerminator = ltNone) then begin + FreeMem(FFixedLine, FixedLineLength); + FFixedLine := nil; + end; + {set the new value} + FLineTerm := aValue; + {if there is no terminator now, allocate the line buffer} + if (LineTerminator = ltNone) then begin + GetMem(FFixedLine, FixedLineLength); + end; + atsResetLineIndex; + end; +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.atsSetLineEndCh(aValue : AnsiChar); +begin + if ((FBufOfs + FBufPos) = 0) then begin + FLineEndCh := aValue; + atsResetLineIndex; + end; +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.atsSetLineLen(aValue : integer); +begin + if (aValue <> FixedLineLength) and ((FBufOfs + FBufPos) = 0) then begin + {validate the new length first} + if (aValue < 1) or (aValue > 1024) then + RaiseStError(EStBufStreamError, stscBadLineLength); + + {set the new value; note that if there is no terminator we need to + free the old line buffer, and then allocate a new one} + if (LineTerminator = ltNone) then + FreeMem(FFixedLine, FixedLineLength); + FLineLen := aValue; + if (LineTerminator = ltNone) then + GetMem(FFixedLine, FixedLineLength); + atsResetLineIndex; + end; +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.bsInitForNewStream; +begin + inherited bsInitForNewStream; + atsResetLineIndex; +end; + +{-----------------------------------------------------------------------------} + +function TStAnsiTextStream.ReadLine : AnsiString; +var + CurPos : longint; + EndPos : longint; + Len : longint; + StLen : longint; +begin + atsGetLine(CurPos, EndPos, Len); + if (LineTerminator = ltNone) then begin + {at this point, Len will either equal FixedLineLength, or it will + be less than it because we read the last line of all and it was + short} + StLen := FixedLineLength; + SetLength(Result, StLen); + if (Len < StLen) then + FillChar(Result[Len+1], StLen-Len, ' '); + end + else {LineTerminator is not ltNone} begin + SetLength(Result, Len); + end; + {read the line} + if Len > 0 then begin + Seek(CurPos, soFromBeginning); + Read(Result[1], Len); + end + else {it's a blank line } + Result := ''; + Seek(EndPos, soFromBeginning); +end; + +{-----------------------------------------------------------------------------} + +function TStAnsiTextStream.ReadLineArray(aCharArray : PAnsiChar; + aLen : TStMemSize) + : TStMemSize; +var + CurPos : longint; + EndPos : longint; + Len : longint; + StLen : longint; +begin + atsGetLine(CurPos, EndPos, Len); + if (LineTerminator = ltNone) then begin + {at this point, Len will either equal FixedLineLength, or it will + be less than it because we read the last line of all and it was + short} + StLen := FixedLineLength; + if (StLen > aLen) then + StLen := aLen; + if (Len < StLen) then + FillChar(aCharArray[Len], StLen-Len, ' '); + Result := StLen; + end + else {LineTerminator is not ltNone} begin + if (Len > aLen) then + Len := aLen; + Result := Len; + end; + Seek(CurPos, soFromBeginning); + Read(aCharArray[0], Len); + Seek(EndPos, soFromBeginning); +end; + +{-----------------------------------------------------------------------------} + +function TStAnsiTextStream.ReadLineZ(aSt : PAnsiChar; aMaxLen : TStMemSize) : PAnsiChar; +var + CurPos : longint; + EndPos : longint; + Len : longint; + StLen : longint; +begin + Result := aSt; + atsGetLine(CurPos, EndPos, Len); + if (LineTerminator = ltNone) then begin + {at this point, Len will either equal FixedLineLength, or it will + be less than it because we read the last line of all and it was + short} + StLen := FixedLineLength; + if (StLen > aMaxLen) then + StLen := aMaxLen; + if (Len < StLen) then + FillChar(Result[Len], StLen-Len, ' '); + Result[StLen] := #0; + end + else {LineTerminator is not ltNone} begin + if (Len > aMaxLen) then + Len := aMaxLen; + Result[Len] := #0; + end; + Seek(CurPos, soFromBeginning); + Read(Result[0], Len); + Seek(EndPos, soFromBeginning); +end; + +{-----------------------------------------------------------------------------} + +function TStAnsiTextStream.SeekNearestLine(aOffset : longint) : longint; +var + CurLine : longint; + CurOfs : longint; + CurPos : longint; + EndPos : longint; + Len : longint; + i : longint; + Done : boolean; + L, R, M : integer; +begin + {if the offset we want is for the current line, reposition at the + current line offset, return the current line number and exit} + if (aOffset = FLineCurOfs) then begin + Seek(FLineCurOfs, soFromBeginning); + Result := FLineCurrent; + Exit; + end; + {if the offset requested is less than or equal to zero, just + position at line zero (ie, the start of the stream)} + if (aOffset <= 0) then begin + Seek(0, soFromBeginning); + FLineCurrent := 0; + FLineCurOfs := 0; + Result := 0; + Exit; + end; + {if the offset requested is greater than or equal to the size of the + stream, position at the end of the stream (note that if we don't + know the number of lines in the stream yet, FLineCount is set to + -1 and we can't take this shortcut because we need to return the + true value)} + if (FLineCount >= 0) and (aOffset >= FSize) then begin + Seek(0, soFromEnd); + FLineCurrent := FLineCount; + FLineCurOfs := FSize; + Result := FLineCount; + Exit; + end; + {if the offset requested is greater than the top item in the + line index, we shall have to build up the index until we get to the + line we require, or just beyond} + if (aOffset > longint(FLineIndex[FLineInxTop+1])) then begin + {position at the last known line offset} + CurLine := longint(FLineIndex[FLineInxTop]); + CurOfs := longint(FLineIndex[FLineInxTop+1]); + Seek(CurOfs, soFromBeginning); + Done := false; + {continue reading lines in chunks of FLineInxStep and add an index + entry for each chunk} + while not Done do begin + for i := 0 to pred(FLineInxStep) do begin + atsGetLine(CurPos, EndPos, Len); + inc(CurLine); + CurOfs := EndPos; + if (EndPos = FSize) then begin + Done := true; + Break; + end; + end; + if Done then + FLineCount := CurLine + else begin + inc(FLineInxTop, 2); + if (FLineInxTop = (LineIndexCount * 2)) then begin + {we've exhausted the space in the index: rescale} + FLineInxTop := FLineInxTop div 2; + for i := 0 to pred(FLineInxTop) do begin + if Odd(i) then + FLineIndex.Exchange((i*2)-1, i) + else + FLineIndex.Exchange(i*2, i); + end; + FLineInxStep := FLineInxStep * 2; + end; + FLineIndex[FLineInxTop] := pointer(CurLine); + FLineIndex[FLineInxTop+1] := pointer(CurOfs); + if (aOffset <= CurOfs) then + Done := true; + end; + end; + end; + {we can now work out where the nearest item in the index is to the + line we require} + L := 1; + R := FLineInxTop+1; + while (L <= R) do begin + M := (L + R) div 2; + if not Odd(M) then + inc(M); + if (aOffset < longint(FLineIndex[M])) then + R := M - 2 + else if (aOffset > longint(FLineIndex[M])) then + L := M + 2 + else begin + FLineCurrent := longint(FLineIndex[M-1]); + FLineCurOfs := longint(FLineIndex[M]); + Seek(FLineCurOfs, soFromBeginning); + Result := FLineCurrent; + Exit; + end; + end; + {the item at L-2 will have the nearest smaller offset than the + one we want, hence the nearest smaller line is at L-3; start here + and read through the stream forwards} + CurLine := longint(FLineIndex[L-3]); + Seek(longint(FLineIndex[L-2]), soFromBeginning); + while true do begin + atsGetLine(CurPos, EndPos, Len); + inc(CurLine); + if (EndPos > aOffset) then begin + FLineCurrent := CurLine - 1; + FLineCurOfs := CurPos; + Seek(CurPos, soFromBeginning); + Result := CurLine - 1; + Exit; + end + else if (CurLine = FLineCount) or (EndPos = aOffset) then begin + FLineCurrent := CurLine; + FLineCurOfs := EndPos; + Seek(EndPos, soFromBeginning); + Result := CurLine; + Exit; + end; + end; +end; + +{-----------------------------------------------------------------------------} + +function TStAnsiTextStream.SeekLine(aLineNum : longint) : longint; +var + CurLine : longint; + CurOfs : longint; + CurPos : longint; + EndPos : longint; + Len : longint; + i : longint; + Done : boolean; + L, R, M : integer; +begin + {if the line number we want is the current line, reposition at the + current line offset, return the current line number and exit} + if (aLineNum = FLineCurrent) then begin + Seek(FLineCurOfs, soFromBeginning); + Result := FLineCurrent; + Exit; + end; + {if the line number requested is less than or equal to zero, just + position at line zero (ie, the start of the stream)} + if (aLineNum <= 0) then begin + Seek(0, soFromBeginning); + FLineCurrent := 0; + FLineCurOfs := 0; + Result := 0; + Exit; + end; + {if the line number requested is greater than or equal to the line + count, position at the end of the stream (note that if we don't + know the number of lines in the stream yet, FLineCount is set to + -1)} + if (FLineCount >= 0) and (aLineNum > FLineCount) then begin + Seek(0, soFromEnd); + FLineCurrent := FLineCount; + FLineCurOfs := FSize; + Result := FLineCount; + Exit; + end; + {if the line number requested is greater than the top item in the + line index, we shall have to build up the index until we get to the + line we require, or just beyond} + if (aLineNum > longint(FLineIndex[FLineInxTop])) then begin + {position at the last known line offset} + CurLine := longint(FLineIndex[FLineInxTop]); + CurOfs := longint(FLineIndex[FLineInxTop+1]); + Seek(CurOfs, soFromBeginning); + Done := false; + {continue reading lines in chunks of FLineInxStep and add an index + entry for each chunk} + while not Done do begin + for i := 0 to pred(FLineInxStep) do begin + atsGetLine(CurPos, EndPos, Len); + inc(CurLine); + CurOfs := EndPos; + if (EndPos = FSize) then begin + Done := true; + Break; + end; + end; + if Done then + FLineCount := CurLine + else begin + inc(FLineInxTop, 2); + if (FLineInxTop = (LineIndexCount * 2)) then begin + {we've exhausted the space in the index: rescale} + FLineInxTop := FLineInxTop div 2; + for i := 0 to pred(FLineInxTop) do begin + if Odd(i) then + FLineIndex.Exchange((i*2)-1, i) + else + FLineIndex.Exchange(i*2, i); + end; + FLineInxStep := FLineInxStep * 2; + end; + FLineIndex[FLineInxTop] := pointer(CurLine); + FLineIndex[FLineInxTop+1] := pointer(CurOfs); + if (aLineNum <= CurLine) then + Done := true; + end; + end; + end; + {we can now work out where the nearest item in the index is to the + line we require} + L := 0; + R := FLineInxTop; + while (L <= R) do begin + M := (L + R) div 2; + if Odd(M) then + dec(M); + if (aLineNum < longint(FLineIndex[M])) then + R := M - 2 + else if (aLineNum > longint(FLineIndex[M])) then + L := M + 2 + else begin + FLineCurrent := longint(FLineIndex[M]); + FLineCurOfs := longint(FLineIndex[M+1]); + Seek(FLineCurOfs, soFromBeginning); + Result := FLineCurrent; + Exit; + end; + end; + {the item at L-2 will have the nearest smaller line number than the + one we want; start here and read through the stream forwards} + CurLine := longint(FLineIndex[L-2]); + Seek(longint(FLineIndex[L-1]), soFromBeginning); + while true do begin + atsGetLine(CurPos, EndPos, Len); + inc(CurLine); + if (CurLine = FLineCount) or (CurLine = aLineNum) then begin + FLineCurrent := CurLine; + FLineCurOfs := EndPos; + Seek(EndPos, soFromBeginning); + Result := CurLine; + Exit; + end; + end; +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.WriteLine(const aSt : AnsiString); +var + Len : Integer; +begin + Len := Length(aSt); + if Len > 0 then + WriteLineArray(PAnsiChar(aSt), Len) + else + WriteLineArray('', 0); +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.WriteLineArray(aCharArray : PAnsiChar; + aLen : TStMemSize); +var + C : AnsiChar; +begin + if (aCharArray = nil) then + aLen := 0; + if (LineTerminator = ltNone) then begin + if (aLen >= FixedLineLength) then + Write(aCharArray[0], FixedLineLength) + else begin + FillChar(FFixedLine[aLen], FixedLineLength-aLen, ' '); + if (aLen > 0) then + Move(aCharArray[0], FFixedLine[0], aLen); + Write(FFixedLine[0], FixedLineLength); + end; + end + else begin + if (aLen > 0) then + Write(aCharArray[0], aLen); + case LineTerminator of + ltNone : {this'll never get hit}; + ltCR : Write(LineTerm[ltCR], 1); + ltLF : Write(LineTerm[ltLF], 1); + ltCRLF : Write(LineTerm[ltCRLF], 2); + ltOther: begin + C := LineTermChar; + Write(C, 1); + end; + else + RaiseStError(EStBufStreamError, stscBadTerminator); + end; + end; +end; + +{-----------------------------------------------------------------------------} + +procedure TStAnsiTextStream.WriteLineZ(aSt : PAnsiChar); +var + LenSt : TStMemSize; +begin + if (aSt = nil) then + LenSt := 0 + else + LenSt := StrLen(aSt); + WriteLineArray(aSt, LenSt); +end; + +{$IFNDEF FPC} +{-----------------------------------------------------------------------------} +{ TStMemoryMappedFile } +{-----------------------------------------------------------------------------} + +constructor TStMemoryMappedFile.Create(const FileName : string; {!!.02} + MaxSize : Cardinal; + ReadOnly : Boolean; + SharedData : Boolean); +var + RO1, + RO2, + RO3, + RO4, + FHi : DWORD; + SetSize: Boolean; +begin + inherited Create; + + FMutex := CreateMutex(nil, False, nil); + FSharedData := SharedData; + if (FSharedData) then + FHeaderSize := SizeOf(Word) + SizeOf(Cardinal) + else + FHeaderSize := 0; + + FReadOnly := ReadOnly; + if (SharedData) then + FReadOnly := False; + if (FReadOnly) then begin + RO1 := GENERIC_READ; + RO2 := FILE_ATTRIBUTE_READONLY; + RO3 := PAGE_READONLY; + RO4 := FILE_MAP_READ; + FMaxHi := 0; + FMaxLo := 0; + end else begin + RO1 := GENERIC_READ or GENERIC_WRITE; + RO2 := FILE_ATTRIBUTE_NORMAL; + RO3 := PAGE_READWRITE; + RO4 := FILE_MAP_WRITE; + FMaxHi := 0; + FMaxLo := MaxSize; + end; + + if (not SharedData) then begin + FHandle := CreateFile(PChar(FileName), + RO1, + FILE_SHARE_READ or FILE_SHARE_WRITE, + nil, + OPEN_ALWAYS, + RO2, + 0); + + if (FHandle = INVALID_HANDLE_VALUE) then + RaiseStError(EStMMFileError, stscCreateFileFailed); + + {reset FMaxLo if file is read/write and less < FileSize} + {the result is that the file size cannot be changed but the contents can} + {still be modified} + FDataSize := GetFileSize(FHandle, @FHi); + if (FDataSize <> $FFFFFFFF) then begin + if (not ReadOnly) and (FDataSize > FMaxLo) then + FMaxLo := FDataSize; + end else begin + CloseHandle(FHandle); + RaiseStError(EStMMFileError, stscGetSizeFailed); + end; + end else + FDataSize := 0; + + if (not SharedData) then begin + FMapObj := CreateFileMapping(FHandle, nil, RO3, FMaxHi, FMaxLo, nil); + SetSize := False; + end else begin + if (FMaxLo > (High(Cardinal) - FHeaderSize)) then + FMaxLo := High(Cardinal) - FHeaderSize + else + FMaxLo := FMaxLo + FHeaderSize; + FMapObj := CreateFileMapping(THandle($FFFFFFFF), nil, RO3, + FMaxHi, FMaxLo, 'STMMFILE1'); + SetSize := (GetLastError = ERROR_ALREADY_EXISTS); + end; + + if (FMapObj = INVALID_HANDLE_VALUE) then + RaiseStError(EStMMFileError, stscFileMappingFailed); + + FBuffer := MapViewOfFile(FMapObj, RO4, 0, 0, FMaxLo); + if (not Assigned(FBuffer)) then + RaiseStError(EStMMFileError, stscCreateViewFailed); + + if (SharedData) then begin + if (SetSize) then + Move(PByteArray(FBuffer)[SizeOf(Word)-1], FDataSize, SizeOf(Cardinal)) + else begin + Move(FHeaderSize, PByteArray(FBuffer)[0], SizeOf(Word)); + FDataSize := 0; + Move(FDataSize, PByteArray(FBuffer)[SizeOf(Word)-1], SizeOf(Cardinal)); + end; + end; + {set position to beginning} + FPos := FHeaderSize; +end; + +{-----------------------------------------------------------------------------} + +destructor TStMemoryMappedFile.Destroy; +begin +{Close the View and Mapping object} + UnmapViewOfFile(FBuffer); + FBuffer := nil; + CloseHandle(FMapObj); + + if (not SharedData) then begin +{set the file pointer to the end of the actual data} + SetFilePointer(FHandle, FDataSize, nil, FILE_BEGIN); +{set the EOF marker to the end of actual data} + SetEndOfFile(FHandle); + CloseHandle(FHandle); + end; + + {now the Mutex can be cleared} + CloseHandle(FMutex); + FMutex := 0; + + inherited Destroy; +end; + +{-----------------------------------------------------------------------------} + +function TStMemoryMappedFile.GetDataSize : Cardinal; +begin + Move(PByteArray(FBuffer)[SizeOf(Word)-1], FDataSize, SizeOf(Cardinal)); + Result := FDataSize; +end; + +{-----------------------------------------------------------------------------} + +function TStMemoryMappedFile.Read(var Buffer; Count : Longint) : Longint; +var +// ByteArray : TByteArray absolute Buffer; {!!.02} + ByteArray : PByte; {!!.02} +begin + ByteArray := @Buffer; {!!.02} + {check to make sure that the read does not go beyond the actual data} + if (((FPos-FHeaderSize) + DWORD(Count)) > FDataSize) then + Count := FDataSize - FPos + FHeaderSize; + + if (SharedData) then begin + WaitForSingleObject(FMutex, INFINITE); + try +// Move(PByteArray(FBuffer)[FPos], ByteArray[0], Count); {!!.02} + Move(PByteArray(FBuffer)[FPos], ByteArray^, Count); {!!.02} + Inc(FPos, Count); + Result := Count; + finally + ReleaseMutex(FMutex); + end; + end else begin +// Move(PByteArray(FBuffer)[FPos], ByteArray[0], Count); {!!.02} + Move(PByteArray(FBuffer)[FPos], ByteArray^, Count); {!!.02} + Inc(FPos, Count); + Result := Count; + end; +end; + +{-----------------------------------------------------------------------------} + +function TStMemoryMappedFile.Write(const Buffer; Count : Longint) : Longint; +var +// ByteArray : TByteArray absolute Buffer; {!!.02} + ByteArray : PByte; {!!.02} +begin + ByteArray := @Buffer; {!!.02} + if (ReadOnly) then begin + Result := 0; + Exit; + end; + + {check that the write does not go beyond the maximum file size} + if ((FPos + DWORD(Count)) > pred(FMaxLo)) then + Count := pred(FMaxLo - FPos); + + if (SharedData) then begin + WaitForSingleObject(FMutex, INFINITE); + try +// Move(ByteArray[0], PByteArray(FBuffer)[FPos], Count); {!!.02} + Move(ByteArray^, PByteArray(FBuffer)[FPos], Count); {!!.02} + Inc(FPos, Count); + {if the write went beyond the previous end of data, update FDataSize} + if ((FPos-FHeaderSize) > FDataSize) then + FDataSize := FPos-FHeaderSize; + Move(FDataSize, PByteArray(FBuffer)[SizeOf(Word)-1], SizeOf(Cardinal)); + Result := Count; + finally + ReleaseMutex(FMutex); + end; + end else begin +// Move(ByteArray[0], PByteArray(FBuffer)[FPos], Count); {!!.02} + Move(ByteArray^, PByteArray(FBuffer)[FPos], Count); {!!.02} + Inc(FPos, Count); + {if the write went beyond the previous end of data, update FDataSize} + if ((FPos-FHeaderSize) > FDataSize) then + FDataSize := FPos-FHeaderSize; + Move(FDataSize, PByteArray(FBuffer)[SizeOf(Word)-1], SizeOf(Cardinal)); + Result := Count; + end; +end; + +{-----------------------------------------------------------------------------} + +function TStMemoryMappedFile.Seek(Offset : Longint; Origin : Word) : Longint; +begin + if (SharedData) then begin + WaitForSingleObject(FMutex, INFINITE); + try + case Origin of + {$WARNINGS OFF} + soFromBeginning : FPos := Offset + FHeaderSize; + soFromCurrent : FPos := FPos + Offset + FHeaderSize; + {the seek should be based on actual data, not the mapped size since} + {the "data" between FDataSize and the mapped size is undefined} + soFromEnd : FPos := FDataSize + Offset + FHeaderSize; + {$WARNINGS ON} + else + RaiseStError(EStMMFileError, stscBadOrigin); + end; + + {force the new position to be valid} + if ((FPos-FHeaderSize) > FDataSize) then + FPos := FDataSize + FHeaderSize; + Result := FPos; + finally + ReleaseMutex(FMutex); + end; + end else begin + {$WARNINGS OFF} + case Origin of + soFromBeginning : FPos := Offset + FHeaderSize; + soFromCurrent : FPos := FPos + Offset + FHeaderSize; + {the seek should be based on actual data, not the mapped size since} + {the "data" between FDataSize and the mapped size is undefined} + soFromEnd : FPos := FDataSize + Offset + FHeaderSize; + else + RaiseStError(EStMMFileError, stscBadOrigin); + end; + {$WARNINGS ON} + + {force the new position to be valid} + if ((FPos-FHeaderSize) > FDataSize) then + FPos := FDataSize + FHeaderSize; + Result := FPos; + end; +end; +{$ENDIF} +{-----------------------------------------------------------------------------} + +end. + diff --git a/components/systools/source/run/ststrs.pas b/components/systools/source/run/ststrs.pas new file mode 100644 index 000000000..d63fe1d5e --- /dev/null +++ b/components/systools/source/run/ststrs.pas @@ -0,0 +1,3408 @@ +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StStrS.pas 4.04 *} +{*********************************************************} +{* SysTools: Short string routines *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} +//{$I StDefine.inc} + +unit StStrS; + +interface + +uses + {$IFDEF FPC} + LCLIntf, LCLType, StrUtils, + {$ELSE} + Windows, + {$ENDIF} + Classes, + SysUtils, + StConst, + StBase; + + {-------- Numeric conversion -----------} + +function HexBS(B : Byte) : ShortString; + {-Return the hex string for a byte.} + +function HexWS(W : Word) : ShortString; + {-Return the hex string for a word.} + +function HexLS(L : LongInt) : ShortString; + {-Return the hex string for a long integer.} + +function HexPtrS(P : Pointer) : ShortString; + {-Return the hex string for a pointer.} + +function BinaryBS(B : Byte) : ShortString; + {-Return a binary string for a byte.} + +function BinaryWS(W : Word) : ShortString; + {-Return the binary string for a word.} + +function BinaryLS(L : LongInt) : ShortString; + {-Return the binary string for a long integer.} + +function OctalBS(B : Byte) : ShortString; + {-Return an octal string for a byte.} + +function OctalWS(W : Word) : ShortString; + {-Return an octal string for a word.} + +function OctalLS(L : LongInt) : ShortString; + {-Return an octal string for a long integer.} + +function Str2Int16S(const S : ShortString; var I : SmallInt) : Boolean; + {-Convert a string to an SmallInt.} + +function Str2WordS(const S : ShortString; var I : Word) : Boolean; + {-Convert a string to a word.} + +function Str2LongS(const S : ShortString; var I : LongInt) : Boolean; + {-Convert a string to a long integer.} + +{$IFDEF VER93} +function Str2RealS(const S : ShortString; var R : Double) : Boolean; +{$ELSE} + {-Convert a string to a real.} +function Str2RealS(const S : ShortString; var R : Real) : Boolean; +{$ENDIF} + +function Str2ExtS(const S : ShortString; var R : Extended) : Boolean; + {-Convert a string to an extended.} + +function Long2StrS(L : LongInt) : ShortString; + {-Convert an integer type to a string.} + +function Real2StrS(R : Double; Width : Byte; Places : ShortInt) : ShortString; + {-Convert a real to a string.} + +function Ext2StrS(R : Extended; Width : Byte; Places : ShortInt) : ShortString; + {-Convert an extended to a string.} + +function ValPrepS(const S : ShortString) : ShortString; + {-Prepares a string for calling Val.} + + + {-------- General purpose string manipulation --------} + +function CharStrS(C : AnsiChar; Len : Cardinal) : ShortString; + {-Return a string filled with the specified character.} + +function PadChS(const S : ShortString; C : AnsiChar; Len : Cardinal) : ShortString; + {-Pad a string on the right with a specified character.} + +function PadS(const S : ShortString; Len : Cardinal) : ShortString; + {-Pad a string on the right with spaces.} + +function LeftPadChS(const S : ShortString; C : AnsiChar; Len : Cardinal) : ShortString; + {-Pad a string on the left with a specified character.} + +function LeftPadS(const S : ShortString; Len : Cardinal) : ShortString; + {-Pad a string on the left with spaces.} + +function TrimLeadS(const S : ShortString) : ShortString; + {-Return a string with leading white space removed.} + +function TrimTrailS(const S : ShortString) : ShortString; + {-Return a string with trailing white space removed.} + +function TrimS(const S : ShortString) : ShortString; + {-Return a string with leading and trailing white space removed.} + +function TrimSpacesS(const S : ShortString) : ShortString; + {-Return a string with leading and trailing spaces removed.} + +function CenterChS(const S : ShortString; C : AnsiChar; Len : Cardinal) : ShortString; + {-Pad a string on the left and right with a specified character.} + +function CenterS(const S : ShortString; Len : Cardinal) : ShortString; + {-Pad a string on the left and right with spaces.} + +{$IFNDEF FPC} +function EntabS(const S : ShortString; TabSize : Byte) : ShortString; + {-Convert blanks in a string to tabs.} + +function DetabS(const S : ShortString; TabSize : Byte) : ShortString; + {-Expand tabs in a string to blanks.} +{$ENDIF} + +function ScrambleS(const S, Key : ShortString) : ShortString; + {-Encrypt / Decrypt string with enhanced XOR encryption.} + +function SubstituteS(const S, FromStr, ToStr : ShortString) : ShortString; + {-Map the characters found in FromStr to the corresponding ones in ToStr.} + +function FilterS(const S, Filters : ShortString) : ShortString; + {-Remove characters from a string. The characters to remove are specified in + ChSet.} + + {--------------- Word / Char manipulation -------------------------} + +function CharExistsS(const S : ShortString; C : AnsiChar) : Boolean; overload; +function CharExistsS(const S : String; C : Char) : Boolean; overload; + {-Determines whether a given character exists in a string. } + +function CharCountS(const S : ShortString; C : AnsiChar) : Byte; + {-Count the number of a given character in a string. } + +function WordCountS(const S, WordDelims : ShortString) : Cardinal; + {-Given an array of word delimiters, return the number of words in a string.} + +function WordPositionS(N : Cardinal; const S, WordDelims : ShortString; + var Pos : Cardinal) : Boolean; + {-Given an array of word delimiters, set Pos to the start position of the + N'th word in a string. Result indicates success/failure.} + +function ExtractWordS(N : Cardinal; const S, WordDelims : ShortString) : ShortString; + {-Given an array of word delimiters, return the N'th word in a string.} + +function AsciiCountS(const S, WordDelims : ShortString; Quote : AnsiChar) : Cardinal; + {-Return the number of words in a string.} + +function AsciiPositionS(N : Cardinal; const S, WordDelims : ShortString; + Quote : AnsiChar; var Pos : Cardinal) : Boolean; + {-Return the position of the N'th word in a string.} + +function ExtractAsciiS(N : Cardinal; const S, WordDelims : ShortString; + Quote : AnsiChar) : ShortString; + {-Given an array of word delimiters, return the N'th word in a string. Any + text within Quote characters is counted as one word.} + +procedure WordWrapS(const InSt : ShortString; var OutSt, Overlap : ShortString; + Margin : Cardinal; PadToMargin : Boolean); + {-Wrap a text string at a specified margin.} + + {--------------- String comparison and searching -----------------} +function CompStringS(const S1, S2 : ShortString) : Integer; + {-Compare two strings.} + +function CompUCStringS(const S1, S2 : ShortString) : Integer; + {-Compare two strings. This compare is not case sensitive.} + +function SoundexS(const S : ShortString) : ShortString; + {-Return 4 character soundex of an input string.} + +function MakeLetterSetS(const S : ShortString) : Longint; + {-Return a bit-mapped long storing the individual letters contained in S.} + +procedure BMMakeTableS(const MatchString : ShortString; var BT : BTable); + {-Build a Boyer-Moore link table} + +function BMSearchS(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : ShortString ; var Pos : Cardinal) : Boolean; + {-Use the Boyer-Moore search method to search a buffer for a string.} + +function BMSearchUCS(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : ShortString ; var Pos : Cardinal) : Boolean; + {-Use the Boyer-Moore search method to search a buffer for a string. This + search is not case sensitive.} + + {--------------- DOS pathname parsing -----------------} + +function DefaultExtensionS(const Name, Ext : ShortString) : ShortString; + {-Return a file name with a default extension attached.} + +function ForceExtensionS(const Name, Ext : ShortString) : ShortString; + {-Force the specified extension onto the file name.} + +function JustFilenameS(const PathName : ShortString) : ShortString; + {-Return just the filename and extension of a pathname.} + +function JustNameS(const PathName : ShortString) : ShortString; + {-Return just the filename (no extension, path, or drive) of a pathname.} + +function JustExtensionS(const Name : ShortString) : ShortString; + {-Return just the extension of a pathname.} + +function JustPathnameS(const PathName : ShortString) : ShortString; + {-Return just the drive and directory portion of a pathname.} + +function AddBackSlashS(const DirName : ShortString) : ShortString; + {-Add a default backslash to a directory name.} + +function CleanPathNameS(const PathName : ShortString) : ShortString; + {-Return a pathname cleaned up as DOS does it.} + +function HasExtensionS(const Name : ShortString; var DotPos : Cardinal) : Boolean; + {-Determine if a pathname contains an extension and, if so, return the + position of the dot in front of the extension.} + + {------------------ Formatting routines --------------------} + +function CommaizeS(L : LongInt) : ShortString; + {-Convert a long integer to a string with commas.} + +function CommaizeChS(L : Longint; Ch : AnsiChar) : ShortString; + {-Convert a long integer to a string with Ch in comma positions.} + +function FloatFormS(const Mask : ShortString ; R : TstFloat ; const LtCurr, + RtCurr : ShortString ; Sep, DecPt : AnsiChar) : ShortString; + {-Return a formatted string with digits from R merged into mask.} + +function LongIntFormS(const Mask : ShortString ; L : LongInt ; const LtCurr, + RtCurr : ShortString ; Sep : AnsiChar) : ShortString; + {-Return a formatted string with digits from L merged into mask.} + +function StrChPosS(const P : string; C : Char; var Pos : Cardinal) : Boolean; overload; +function StrChPosS(const P : ShortString; C : AnsiChar; var Pos : Cardinal) : Boolean; overload; + + {-Return the position of a specified character within a string.} + +function StrStPosS(const P, S : ShortString; var Pos : Cardinal) : Boolean; + {-Return the position of a specified substring within a string.} + +function StrStCopyS(const S : ShortString; Pos, Count : Cardinal) : ShortString; + {-Copy characters at a specified position in a string.} + +function StrChInsertS(const S : ShortString; C : AnsiChar; Pos : Cardinal) : ShortString; + {-Insert a character into a string at a specified position.} + +function StrStInsertS(const S1, S2 : ShortString; Pos : Cardinal) : ShortString; + {-Insert a string into another string at a specified position.} + +function StrChDeleteS(const S : ShortString; Pos : Cardinal) : ShortString; + {-Delete the character at a specified position in a string.} + +function StrStDeleteS(const S : ShortString; Pos, Count : Cardinal) : ShortString; + {-Delete characters at a specified position in a string.} + + +{-------------------------- New Functions -----------------------------------} + +function ContainsOnlyS(const S, Chars : ShortString; + var BadPos : Cardinal) : Boolean; + +function ContainsOtherThanS(const S, Chars : ShortString; + var BadPos : Cardinal) : Boolean; + +function CopyLeftS(const S : ShortString; Len : Cardinal) : ShortString; + {-Return the left Len characters of a string} + +function CopyMidS(const S : ShortString; First, Len : Cardinal) : ShortString; + {-Return the mid part of a string} + +function CopyRightS(const S : ShortString; First : Cardinal) : ShortString; + {-Return the right Len characters of a string} + +function CopyRightAbsS(const S : ShortString; NumChars : Cardinal) : ShortString; + {-Return NumChar characters starting from end} + +function CopyFromNthWordS(const S, WordDelims : ShortString; + const AWord : ShortString; N : Cardinal; {!!.02} + var SubString : ShortString) : Boolean; + +function DeleteFromNthWordS(const S, WordDelims : ShortString; + AWord : ShortString; N : Cardinal; + var SubString : ShortString) : Boolean; + +function CopyFromToWordS(const S, WordDelims, Word1, Word2 : ShortString; + N1, N2 : Cardinal; + var SubString : ShortString) : Boolean; + +function DeleteFromToWordS(const S, WordDelims, Word1, Word2 : ShortString; + N1, N2 : Cardinal; + var SubString : ShortString) : Boolean; + +function CopyWithinS(const S, Delimiter : ShortString; + Strip : Boolean) : ShortString; + +function DeleteWithinS(const S, Delimiter : ShortString) : ShortString; + +function ExtractTokensS(const S, Delims : ShortString; + QuoteChar : AnsiChar; + AllowNulls : Boolean; + Tokens : TStrings) : Cardinal; + +function IsChAlphaS(C : Char) : Boolean; + {-Returns true if Ch is an alpha} + +function IsChNumericS(C : AnsiChar; const Numbers : ShortString) : Boolean; + {-Returns true if Ch in numeric set} + +function IsChAlphaNumericS(C : Char; const Numbers : ShortString) : Boolean; + {-Returns true if Ch is an alpha or numeric} + +function IsStrAlphaS(const S : string) : Boolean; + {-Returns true if all characters in string are an alpha} + +function IsStrNumericS(const S, Numbers : ShortString) : Boolean; + {-Returns true if all characters in string are in numeric set} + +function IsStrAlphaNumericS(const S, Numbers : String) : Boolean; + {-Returns true if all characters in string are alpha or numeric} + +function LastWordS(const S, WordDelims, AWord : ShortString; + var Position : Cardinal) : Boolean; + {-returns the position in a string of the last instance of a given word} + +function LastWordAbsS(const S, WordDelims : ShortString; + var Position : Cardinal) : Boolean; + {-returns the position in a string of the last word} + +function LastStringS(const S, AString : ShortString; + var Position : Cardinal) : Boolean; + {-returns the position in a string of the last instance of a given string} + +function LeftTrimCharsS(const S, Chars : ShortString) : ShortString; + {-strips given characters from the beginning of a string} + +function KeepCharsS(const S, Chars : ShortString) : ShortString; + {-returns a string containing only those characters in a given set} + +function RepeatStringS(const RepeatString : ShortString; + var Repetitions : Cardinal; + MaxLen : Cardinal) : ShortString; + {-creates a string of up to Repetition instances of a string} + +function ReplaceStringS(const S, OldString, NewString : ShortString; + N : Cardinal; + var Replacements : Cardinal) : ShortString; + {-replaces a substring with up to Replacements instances of a string} + +function ReplaceStringAllS(const S, OldString, NewString : ShortString; + var Replacements : Cardinal) : ShortString; + {-replaces all instances of a substring with one or more instances of a string} + +function ReplaceWordS(const S, WordDelims, OldWord, NewWord : ShortString; + N : Cardinal; + var Replacements : Cardinal) : ShortString; + {-replaces a given word with one or more instances of a string} + +function ReplaceWordAllS(const S, WordDelims, OldWord, NewWord : ShortString; + var Replacements : Cardinal) : ShortString; + {-replaces all instances of a word with one or more instances of a string} + +function RightTrimCharsS(const S, Chars : ShortString) : ShortString; + {-removes those characters at the end of a string contained in a set of characters} + +function StrWithinS(const S, SearchStr : ShortString; + Start : Cardinal; + var Position : Cardinal) : boolean; + {-finds the position of a substring within a string starting at a given point} + +function TrimCharsS(const S, Chars : ShortString) : ShortString; + {-removes trailing and leading characters defined by a string from a string} + +function WordPosS(const S, WordDelims, AWord : ShortString; + N : Cardinal; var Position : Cardinal) : Boolean; + {-returns the Nth instance of a word within a string} + + +implementation + + + {-------- Numeric conversion -----------} + +function HexBS(B : Byte) : ShortString; + {-Return the hex string for a byte.} +begin + Result[0] := #2; + Result[1] := StHexDigits[B shr 4]; + Result[2] := StHexDigits[B and $F]; +end; + +function HexWS(W : Word) : ShortString; + {-Return the hex string for a word.} +begin + Result[0] := #4; + Result[1] := StHexDigits[hi(W) shr 4]; + Result[2] := StHexDigits[hi(W) and $F]; + Result[3] := StHexDigits[lo(W) shr 4]; + Result[4] := StHexDigits[lo(W) and $F]; +end; + +function HexLS(L : LongInt) : ShortString; + {-Return the hex string for a long integer.} +begin + Result := HexWS(HiWord(DWORD(L))) + HexWS(LoWord(DWORD(L))); {!!.02} +end; + +function HexPtrS(P : Pointer) : ShortString; + {-Return the hex string for a pointer.} +begin + Result := HexLS(LongInt(P)); {!!.02} +end; + +function BinaryBS(B : Byte) : ShortString; + {-Return a binary string for a byte.} +var + I, N : Cardinal; +begin + N := 1; + Result[0] := #8; + for I := 7 downto 0 do begin + Result[N] := StHexDigits[Ord(B and (1 shl I) <> 0)]; {0 or 1} + Inc(N); + end; +end; + +function BinaryWS(W : Word) : ShortString; + {-Return the binary string for a word.} +var + I, N : Cardinal; +begin + N := 1; + Result[0] := #16; + for I := 15 downto 0 do begin + Result[N] := StHexDigits[Ord(W and (1 shl I) <> 0)]; {0 or 1} + Inc(N); + end; +end; + +function BinaryLS(L : LongInt) : ShortString; + {-Return the binary string for a long integer.} +var + I : Longint; + N : Byte; +begin + N := 1; + Result[0] := #32; + for I := 31 downto 0 do begin + Result[N] := StHexDigits[Ord(L and LongInt(1 shl I) <> 0)]; {0 or 1} + Inc(N); + end; +end; + +function OctalBS(B : Byte) : ShortString; + {-Return an octal string for a byte.} +var + I : Cardinal; +begin + Result[0] := #3; + for I := 0 to 2 do begin + Result[3-I] := StHexDigits[B and 7]; + B := B shr 3; + end; +end; + +function OctalWS(W : Word) : ShortString; + {-Return an octal string for a word.} +var + I : Cardinal; +begin + Result[0] := #6; + for I := 0 to 5 do begin + Result[6-I] := StHexDigits[W and 7]; + W := W shr 3; + end; +end; + +function OctalLS(L : LongInt) : ShortString; + {-Return an octal string for a long integer.} +var + I : Cardinal; +begin + Result[0] := #12; + for I := 0 to 11 do begin + Result[12-I] := StHexDigits[L and 7]; + L := L shr 3; + end; +end; + +function Str2Int16S(const S : ShortString; var I : SmallInt) : Boolean; + {-Convert a string to an SmallInt.} + +var + ec : Integer; +begin + ValSmallint(S, I, ec); + if (ec = 0) then + Result := true + else begin + Result := false; + if (ec < 0) then + I := succ(length(S)) + else + I := ec; + end; +end; + +function Str2WordS(const S : ShortString; var I : Word) : Boolean; + {-Convert a string to a word.} + +var + ec : Integer; +begin + ValWord(S, I, ec); + if (ec = 0) then + Result := true + else begin + Result := false; + if (ec < 0) then + I := succ(length(S)) + else + I := ec; + end; +end; + +function Str2LongS(const S : ShortString; var I : LongInt) : Boolean; + {-Convert a string to a long integer.} + +var + ec : Integer; +begin + ValLongint(S, I, ec); + if (ec = 0) then + Result := true + else begin + Result := false; + if (ec < 0) then + I := succ(length(S)) + else + I := ec; + end; +end; + +{$IFDEF VER93} +function Str2RealS(const S : ShortString; var R : Double) : Boolean; +{$ELSE} + {-Convert a string to a real.} +function Str2RealS(const S : ShortString; var R : Real) : Boolean; +{$ENDIF} + {-Convert a string to a real.} +var + Code : Integer; + St : ShortString; + SLen : Byte absolute St; +begin + St := S; + {trim trailing blanks} + while St[SLen] = ' ' do + Dec(SLen); + Val(ValPrepS(St), R, Code); + if Code <> 0 then begin + R := Code; + Result := False; + end else + Result := True; +end; + +function Str2ExtS(const S : ShortString; var R : Extended) : Boolean; + {-Convert a string to an extended.} +var + Code : Integer; + P : ShortString; + PLen : Byte absolute P; +begin + P := S; + {trim trailing blanks} + while P[PLen] = ' ' do + Dec(PLen); + Val(ValPrepS(P), R, Code); + if Code <> 0 then begin + R := Code; + Result := False; + end else + Result := True; +end; + +function Long2StrS(L : LongInt) : ShortString; + {-Convert an integer type to a string.} +begin + Str(L, Result); +end; + +function Real2StrS(R : Double; Width : Byte; Places : ShortInt) : ShortString; + {-Convert a real to a string.} +begin + Str(R:Width:Places, Result); +end; + +function Ext2StrS(R : Extended; Width : Byte; Places : ShortInt) : ShortString; + {-Convert an extended to a string.} +begin + Str(R:Width:Places, Result); +end; + +function ValPrepS(const S : ShortString) : ShortString; + {-Prepares a string for calling Val.} +var + P : Cardinal; +begin + Result := TrimSpacesS(S); + if Result <> '' then begin + if StrChPosS(Result, {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator, P) then begin + Result[P] := '.'; + if P = Byte(Result[0]) then + Result[0] := AnsiChar(Pred(P)); + end; + end else begin + Result := '0'; + end; +end; + + {-------- General purpose string manipulation --------} + +function CharStrS(C : AnsiChar; Len : Cardinal) : ShortString; + {-Return a string filled with the specified character.} +begin + if Len = 0 then + Result[0] := #0 + else begin + Result[0] := AnsiChar(Len); + FillChar(Result[1], Len, C); + end; +end; + +function PadChS(const S : ShortString; C : AnsiChar; Len : Cardinal) : ShortString; + {-Pad a string on the right with a specified character.} +var + SLen : Byte absolute S; +begin + if Length(S) >= Len then + Result := S + else begin + if Len > 255 then Len := 255; + Result[0] := AnsiChar(Len); + Move(S[1], Result[1], SLen); + if SLen < 255 then + FillChar(Result[Succ(SLen)], Len-SLen, C); + end; +end; + +function PadS(const S : ShortString; Len : Cardinal) : ShortString; + {-Pad a string on the right with spaces.} +begin + Result := PadChS(S, ' ', Len); +end; + +function LeftPadChS(const S : ShortString; C : AnsiChar; Len : Cardinal) : ShortString; + {-Pad a string on the left with a specified character.} +begin + if Length(S) >= Len then + Result := S + else if Length(S) < 255 then begin + if Len > 255 then Len := 255; + Result[0] := AnsiChar(Len); + Move(S[1], Result[Succ(Word(Len))-Length(S)], Length(S)); + FillChar(Result[1], Len-Length(S), C); + end; +end; + +function LeftPadS(const S : ShortString; Len : Cardinal) : ShortString; + {-Pad a string on the left with spaces.} +begin + Result := LeftPadChS(S, ' ', Len); +end; + +function TrimLeadS(const S : ShortString) : ShortString; + {-Return a string with leading white space removed} +var + I : Cardinal; +begin +{!!.03 - added } + if S = '' then begin + Result := ''; + Exit; + end; +{!!.03 - added end } + I := 1; + while (I <= Length(S)) and (S[I] <= ' ') do + Inc(I); + Move(S[I], Result[1], Length(S)-I+1); + Result[0] := AnsiChar(Length(S)-I+1); +end; + +function TrimTrailS(const S : ShortString) : ShortString; + {-Return a string with trailing white space removed.} +begin + Result := S; + while (Length(Result) > 0) and (Result[Length(Result)] <= ' ') do + Dec(Result[0]); +end; + +function TrimS(const S : ShortString) : ShortString; + {-Return a string with leading and trailing white space removed.} +var + I : Cardinal; + SLen : Byte absolute Result; +begin + Result := S; + while (SLen > 0) and (Result[SLen] <= ' ') do + Dec(SLen); + + I := 1; + while (I <= SLen) and (Result[I] <= ' ') do + Inc(I); + Dec(I); + if I > 0 then + Delete(Result, 1, I); +end; + +function TrimSpacesS(const S : ShortString) : ShortString; + {-Return a string with leading and trailing spaces removed.} +var + I : Word; +begin + Result := S; + while (Length(Result) > 0) and (Result[Length(Result)] = ' ') do + Dec(Result[0]); + I := 1; + while (I <= Length(Result)) and (S[I] = ' ') do + Inc(I); + Dec(I); + if I > 0 then + Delete(Result, 1, I); +end; + +function CenterChS(const S : ShortString; C : AnsiChar; Len : Cardinal) : ShortString; + {-Pad a string on the left and right with a specified character.} +begin + if Length(S) >= Len then + Result := S + else if Length(S) < 255 then begin + if Len > 255 then Len := 255; + Result[0] := AnsiChar(Len); + FillChar(Result[1], Len, C); + Move(S[1], Result[Succ((Len-Length(S)) shr 1)], Length(S)); + end; +end; + +function CenterS(const S : ShortString; Len : Cardinal) : ShortString; + {-Pad a string on the left and right with spaces.} +begin + Result := CenterChS(S, ' ', Len); +end; + +{$IFNDEF FPC} +function EntabS(const S : ShortString; TabSize : Byte) : ShortString; + {-Convert blanks in a string to tabs.} +register; +asm + push ebx { Save registers } + push edi + push esi + + mov esi, eax { ESI => input string } + mov edi, ecx { EDI => output string } + xor ebx, ebx { Initial SpaceCount = 0 } + xor ecx, ecx { Default input length = 0 } + and edx, 0FFh { Default output length = 0 in DH, TabSize in DL } + + mov cl, [esi] { Get input length } + inc esi + or edx, edx { TabSize = 0? } + jnz @@DefLength + mov ecx, edx { Return zero length string if TabSize = 0 } + +@@DefLength: + mov [edi], cl { Store default output length } + inc edi + or ecx, ecx + jz @@Done { Done if empty input string } + inc ch { Current input position=1 } + +@@Next: + or ebx, ebx { Compare SpaceCount to 0 } + jz @@NoTab { If SpaceCount=0 then no tab insert here } + xor eax, eax + mov al, ch { Ipos to AL } + div dl { Ipos DIV TabSize } + cmp ah, 1 { Ipos MOD TabSize = 1 ? } + jnz @@NoTab { If not, no tab insert here } + sub edi, ebx { Remove unused characters from output string } + sub dh, bl { Reduce Olen by SpaceCount } + inc dh { Add one to output length } + xor ebx, ebx { Reset SpaceCount } + mov byte ptr [edi], 09h { Store a tab } + inc edi + +@@NoTab: + mov al, [esi] { Get next input character } + inc esi + cmp cl, ch { End of string? } + jz @@Store { Yes, store character anyway } + inc bl { Increment SpaceCount } + cmp al, 32 { Is character a space? } + jz @@Store { Yes, store it for now } + xor ebx, ebx { Reset SpaceCount } + cmp al, 39 { Is it a quote? } + jz @@Quotes { Yep, enter quote loop } + cmp al, 34 { Is it a doublequote? } + jnz @@Store { Nope, store it } + +@@Quotes: + mov ah, al { Save quote start } + +@@NextQ: + mov [edi], al { Store quoted character } + inc edi + inc dh { Increment output length } + mov al, [esi] { Get next character } + inc esi + inc ch { Increment Ipos } + cmp ch, cl { At end of line? } + jae @@Store { If so, exit quote loop } + cmp al, ah { Matching end quote? } + jnz @@NextQ { Nope, stay in quote loop } + cmp al, 39 { Single quote? } + jz @@Store { Exit quote loop } + cmp byte ptr [esi-2],'\'{ Previous character an escape? } + jz @@NextQ { Stay in if so } + +@@Store: + mov [edi], al { Store last character } + inc edi + inc dh { Increment output length } + inc ch { Increment input position } + jz @@StoreLen { Exit if past 255 } + cmp ch, cl { Compare Ipos to Ilen } + jbe @@Next { Repeat while characters left } + +@@StoreLen: + xor eax, eax + mov al, dh + sub edi, eax + dec edi + mov [edi], dh { Store final length } + +@@Done: + pop esi + pop edi + pop ebx +end; + +function DetabS(const S : ShortString; TabSize : Byte) : ShortString; + {-Expand tabs in a string to blanks.} +register; +asm + push ebx + push edi + push esi + + mov edi, ecx { EDI => output string } + mov esi, eax { ESI => input string } + xor ecx, ecx { Default input length = 0 } + and edx, 0FFh { Default output length = 0 in DH, DL is Tabsize } + xor eax, eax + mov cl, [esi] { Get input length } + inc esi + or edx, edx { TabSize = 0? } + jnz @@DefLength + mov ecx, edx { Return zero length string if TabSize = 0 } + +@@DefLength: + mov [edi], cl { Store default output length } + inc edi + or ecx, ecx + jz @@Done { Done if empty input string } + mov ah, 09h { Store tab in AH } + mov bl, 255 { Maximum length of output } + +@@Next: + mov al, [esi] { Next input character } + inc esi + cmp al, ah { Is it a tab? } + jz @@Tab { Yes, compute next tab stop } + mov [edi], al { No, store to output } + inc edi + inc dh { Increment output length } + cmp dh, bl { 255 characters max } + jz @@StoreLen + dec cl + jnz @@Next { Next character while Olen <= 255 } + jmp @@StoreLen { Loop termination } + +@@Tab: + mov bh, cl { Save input counter } + mov al, dh { Current output length in AL } + and eax, 0FFh { Clear top byte } + div dl { OLen DIV TabSize in AL } + inc al { Round up to next tab position } + mul dl { Next tab position in AX } + or ah, ah { AX > 255? } + jnz @@StoreLen { Can't store it } + sub al, dh { Count of blanks to insert } + add dh, al { New output length in DH } + mov cl, al { Loop counter for blanks } + mov ax, 0920h { Tab in AH, Blank in AL } + rep stosb { Store blanks } + mov cl, bh { Restore input position } + dec cl + jnz @@Next { Back for next input } + +@@StoreLen: + xor eax, eax + mov al, dh + sub edi, eax + dec edi + mov [edi], dh { Store final length } + +@@Done: + pop esi + pop edi + pop ebx +end; +{$ENDIF} + +function ScrambleS(const S, Key : ShortString) : ShortString; + {-Encrypt / Decrypt string with enhanced XOR encryption.} +var + J, LKey, LStr : Byte; + I : Cardinal; +begin + Result := S; + LKey := Length(Key); + LStr := Length(S); + if LKey = 0 then Exit; + if LStr = 0 then Exit; + I := 1; + J := LKey; + while I <= LStr do begin + if J = 0 then + J := LKey; + if (S[I] <> Key[J]) then + Result[I] := AnsiChar(Byte(S[I]) xor Byte(Key[J])); + inc(I); + dec(J); + end; +end; + +function SubstituteS(const S, FromStr, ToStr : ShortString) : ShortString; + {-Map the characters found in FromStr to the corresponding ones in ToStr.} +var + P : Cardinal; + I : Byte; +begin + Result := S; + if Length(FromStr) = Length(ToStr) then + for I := 1 to Length(Result) do begin + if StrChPosS(FromStr, S[I], P) then + Result[I] := ToStr[P]; + end; +end; + +function FilterS(const S, Filters : ShortString) : ShortString; + {-Remove characters from a string. The characters to remove are specified in + ChSet.} +var + I : Cardinal; + Len : Cardinal; +begin + Len := 0; + for I := 1 to Length(S) do + if not CharExistsS(Filters, S[I]) then begin + Inc(Len); + Result[Len] := S[I]; + end; + Result[0] := AnsiChar(Len); +end; + + {--------------- Word / Char manipulation -------------------------} + +function CharExistsS(const S : String; C : Char) : Boolean; overload; +var + I: Integer; +begin + Result := False; + for I := 1 to Length(S) do + begin + if S[I] = C then + begin + Result := True; + Break; + end; + end; +end; + +function CharExistsS(const S : ShortString; C : AnsiChar) : Boolean; overload; + {-Determine whether a given character exists in a string. } +register; +asm + xor ecx, ecx + mov ch, [eax] + inc eax + or ch, ch + jz @@Done + jmp @@5 + +@@Loop: + cmp dl, [eax+3] + jne @@1 + inc cl + jmp @@Done + +@@1: + cmp dl, [eax+2] + jne @@2 + inc cl + jmp @@Done + +@@2: + cmp dl, [eax+1] + jne @@3 + inc cl + jmp @@Done + +@@3: + cmp dl, [eax+0] + jne @@4 + inc cl + jmp @@Done + +@@4: + add eax, 4 + sub ch, 4 + jna @@Done + +@@5: + cmp ch, 4 + jae @@Loop + + cmp ch, 3 + je @@1 + + cmp ch, 2 + je @@2 + + cmp ch, 1 + je @@3 + +@@Done: + xor eax, eax + mov al, cl +end; + +function CharCountS(const S : ShortString; C : AnsiChar) : Byte; + {-Count the number of a given character in a string. } +register; +asm + xor ecx, ecx + mov ch, [eax] + inc eax + or ch, ch + jz @@Done + jmp @@5 + +@@Loop: + cmp dl, [eax+3] + jne @@1 + inc cl + +@@1: + cmp dl, [eax+2] + jne @@2 + inc cl + +@@2: + cmp dl, [eax+1] + jne @@3 + inc cl + +@@3: + cmp dl, [eax+0] + jne @@4 + inc cl + +@@4: + add eax, 4 + sub ch, 4 + jna @@Done + +@@5: + cmp ch, 4 + jae @@Loop + + cmp ch, 3 + je @@1 + + cmp ch, 2 + je @@2 + + cmp ch, 1 + je @@3 + +@@Done: + mov al, cl +end; + +function WordCountS(const S, WordDelims : ShortString) : Cardinal; + {-Given an array of word delimiters, return the number of words in a string.} +var + I : Integer; + SLen : Byte; +begin + Result := 0; + I := 1; + SLen := Length(S); + + while I <= SLen do begin + {skip over delimiters} + while (I <= SLen) and CharExistsS(WordDelims, S[I]) do + Inc(I); + + {if we're not beyond end of S, we're at the start of a word} + if I <= SLen then + Inc(Result); + + {find the end of the current word} + while (I <= SLen) and not CharExistsS(WordDelims, S[I]) do + Inc(I); + end; +end; + +function WordPositionS(N : Cardinal; const S, WordDelims : ShortString; + var Pos : Cardinal) : Boolean; + {-Given an array of word delimiters, set Pos to the start position of the + N'th word in a string. Result indicates success/failure.} +var + I : Cardinal; + Count : Byte; + SLen : Byte absolute S; +begin + Count := 0; + I := 1; + Result := False; + + while (I <= SLen) and (Count <> N) do begin + {skip over delimiters} + while (I <= SLen) and CharExistsS(WordDelims, S[I]) do + Inc(I); + + {if we're not beyond end of S, we're at the start of a word} + if I <= SLen then + Inc(Count); + + {if not finished, find the end of the current word} + if Count <> N then + while (I <= SLen) and not CharExistsS(WordDelims, S[I]) do + Inc(I) + else begin + Pos := I; + Result := True; + end; + end; +end; + +function ExtractWordS(N : Cardinal; const S, WordDelims : ShortString) : ShortString; + {-Given an array of word delimiters, return the N'th word in a string.} +var + I : Cardinal; + Len : Byte; + SLen : Byte absolute S; +begin + Len := 0; + if WordPositionS(N, S, WordDelims, I) then + {find the end of the current word} + while (I <= SLen) and not CharExistsS(WordDelims, S[I]) do begin + {add the I'th character to result} + Inc(Len); + Result[Len] := S[I]; + Inc(I); + end; + Result[0] := AnsiChar(Len); +end; + +function AsciiCountS(const S, WordDelims : ShortString; Quote : AnsiChar) : Cardinal; + {-Return the number of words in a string.} +var + I : Cardinal; + InQuote : Boolean; + SLen : Byte absolute S; +begin + Result := 0; + I := 1; + InQuote := False; + while I <= SLen do begin + {skip over delimiters} + while (I <= SLen) and (S[i] <> Quote) and CharExistsS(WordDelims, S[I]) do + Inc(I); + {if we're not beyond end of S, we're at the start of a word} + if I <= SLen then + Inc(Result); + {find the end of the current word} + while (I <= SLen) and (InQuote or not CharExistsS(WordDelims, S[I])) do begin + if S[I] = Quote then + InQuote := not InQuote; + Inc(I); + end; + end; +end; + +function AsciiPositionS(N : Cardinal; const S, WordDelims : ShortString; + Quote : AnsiChar; var Pos : Cardinal) : Boolean; + {-Return the position of the N'th word in a string.} +var + I : Cardinal; + Count : Byte; + InQuote : Boolean; + SLen : Byte absolute S; +begin + Count := 0; + InQuote := False; + Result := False; + I := 1; + while (I <= SLen) and (Count <> N) do begin + {skip over delimiters} + while (I <= SLen) and (S[I] <> Quote) and CharExistsS(WordDelims, S[I]) do + Inc(I); + {if we're not beyond end of S, we're at the start of a word} + if I <= SLen then + Inc(Count); + {if not finished, find the end of the current word} + if Count <> N then + while (I <= SLen) and (InQuote or not CharExistsS(WordDelims, S[I])) do begin + if S[I] = Quote then + InQuote := not InQuote; + Inc(I); + end + else begin + Pos := I; + Result := True; + end; + end; +end; + +function ExtractAsciiS(N : Cardinal; const S, WordDelims : ShortString; + Quote : AnsiChar) : ShortString; + {-Given an array of word delimiters, return the N'th word in a string. Any + text within Quote characters is counted as one word.} +var + I : Cardinal; + Len : Byte; + SLen : Byte absolute S; + InQuote : Boolean; +begin + Len := 0; + InQuote := False; + if AsciiPositionS(N, S, WordDelims, Quote, I) then + {find the end of the current word} + while (I <= SLen) and ((InQuote) or not CharExistsS(WordDelims, S[I])) do begin + {add the I'th character to result} + Inc(Len); + if S[I] = Quote then + InQuote := not(InQuote); + Result [Len] := S[I]; + Inc(I); + end; + Result [0] := AnsiChar(Len); +end; + +procedure WordWrapS(const InSt : ShortString; var OutSt, Overlap : ShortString; + Margin : Cardinal; PadToMargin : Boolean); + {-Wrap a text string at a specified margin.} +var + EOS, BOS : Cardinal; + InStLen : Byte; + OutStLen : Byte absolute OutSt; + OvrLen : Byte absolute Overlap; +begin + InStLen := Length(InSt); + +{!!.02 - Added } + { handle empty string on input } + if InStLen = 0 then begin + OutSt := ''; + Overlap := ''; + Exit; + end; +{!!.02 - End Added } + + {find the end of the output string} + if InStLen > Margin then begin + {find the end of the word at the margin, if any} + EOS := Margin; + while (EOS <= InStLen) and (InSt[EOS] <> ' ') do + Inc(EOS); + if EOS > InStLen then + EOS := InStLen; + + {trim trailing blanks} + while (InSt[EOS] = ' ') and (EOS > 0) do + Dec(EOS); + + if EOS > Margin then begin + {look for the space before the current word} + while (EOS > 0) and (InSt[EOS] <> ' ') do + Dec(EOS); + + {if EOS = 0 then we can't wrap it} + if EOS = 0 then + EOS := Margin + else + {trim trailing blanks} + while (InSt[EOS] = ' ') and (EOS > 0) do + Dec(EOS); + end; + end else + EOS := InStLen; + + {copy the unwrapped portion of the line} + OutStLen := EOS; + Move(InSt[1], OutSt[1], OutStLen); + + {find the start of the next word in the line} + BOS := EOS+1; + while (BOS <= InStLen) and (InSt[BOS] = ' ') do + Inc(BOS); + + if BOS > InStLen then + OvrLen := 0 + else begin + {copy from the start of the next word to the end of the line} + OvrLen := Succ(InStLen-BOS); + Move(InSt[BOS], Overlap[1], OvrLen); + end; + + {pad the end of the output string if requested} + if PadToMargin and (OutStLen < Margin) then begin + FillChar(OutSt[OutStLen+1], Margin-OutStLen, ' '); + OutStLen := Margin; + end; +end; + + {--------------- String comparison and searching -----------------} +function CompStringS(const S1, S2 : ShortString) : Integer; + {-Compare two strings.} +register; +asm + push edi + mov edi, edx { EDI points to S2 } + push esi + mov esi, eax { ESI points to S1 } + + xor ecx, ecx + + mov dl, [edi] { DL = Length(S2) } + inc edi { EDI points to S2[1] } + mov cl, [esi] + inc esi { CL = Length(S1) - ESI points to S1[1] } + + or eax, -1 { EAX holds temporary result } + + cmp cl, dl { Compare lengths } + je @@EqLen { Lengths equal? } + jb @@Comp { Jump if S1 shorter than S1 } + + inc eax { S1 longer than S2 } + mov cl, dl { Length(S2) in CL } + +@@EqLen: + inc eax { Equal or greater } + +@@Comp: + or ecx, ecx + jz @@Done { Done if either is empty } + + repe cmpsb { Compare until no match or ECX = 0 } + je @@Done { If Equal, result ready based on length } + + mov eax, 1 + ja @@Done { S1 Greater? Return 1 } + or eax, -1 { Else S1 Less, Return -1 } + +@@Done: + pop esi + pop edi +end; + +function CompUCStringS(const S1, S2 : ShortString) : Integer; + {-Compare two strings. This compare is not case sensitive.} +register; +asm + push ebx + push edi { Save registers } + push esi + + mov edi, edx { EDI points to S2 } + mov esi, eax { ESI points to S1 } + + xor eax, eax { EAX holds chars from S1 } + xor ecx, ecx { ECX holds count of chars to compare } + xor edx, edx { DH holds temp result, DL chars from S2 } + or ebx, -1 + + mov al, [edi] { AH = Length(S2) } + inc edi { EDI points to S2[1] } + mov cl, [esi] { CL = Length(S1) - SI points to S1[1] } + inc esi + + cmp cl, al { Compare lengths } + je @@EqLen { Lengths equal? } + jb @@Comp { Jump if S1 shorter than S1 } + + inc ebx { S1 longer than S2 } + mov cl, al { Shorter length in CL } + +@@EqLen: + inc ebx { Equal or greater } + +@@Comp: + or ecx, ecx + jz @@Done { Done if lesser string is empty } + +@@Start: + mov al, [esi] { S1[?] into AL } + inc esi + + push ecx { Save registers } + push edx + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + + mov dl, [edi] { S2[?] into DL } + inc edi { Point EDI to next char in S2 } + mov dh, al + mov al, dl + mov dl, dh + + push ecx { Save registers } + push edx + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + + cmp dl, al { Compare until no match } + jnz @@Output + dec ecx + jnz @@Start + + je @@Done { If Equal, result ready based on length } + +@@Output: + mov ebx, 1 + ja @@Done { S1 Greater? Return 1 } + or ebx, -1 { Else S1 Less, Return -1 } + +@@Done: + mov eax, ebx { Result into AX } + pop esi { Restore Registers } + pop edi + pop ebx +end; + +function SoundexS(const S : ShortString) : ShortString; assembler; + {-Return 4 character soundex of an input string} +register; +const + SoundexTable : array[0..255] of Char = + (#0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, + { A B C D E F G H I J K L M } + #0, '1', '2', '3', #0, '1', '2', #0, #0, '2', '2', '4', '5', + { N O P Q R S T U V W X Y X } + '5', #0, '1', '2', '6', '2', '3', #0, '1', #0, '2', #0, '2', + #0, #0, #0, #0, #0, #0, + { a b c d e f g h i j k l m } + #0, '1', '2', '3', #0, '1', '2', #0, #0, '2', '2', '4', '5', + { n o p q r s t u v w x y x } + '5', #0, '1', '2', '6', '2', '3', #0, '1', #0, '2', #0, '2', + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0, #0, #0, #0, #0, #0, #0, #0, + #0, #0, #0); +asm + push edi + mov edi, edx { EDI => output string } + push ebx + push esi + + mov esi, eax { ESI => input string } + mov byte ptr [edi], 4 { Prepare output string to be #4'0000' } + mov dword ptr [edi+1], '0000' + inc edi + + mov cl, byte ptr [esi] + inc esi + or cl, cl { Exit if null string } + jz @@Done + + xor eax, eax + mov al, [esi] { Get first character of input string } + inc esi + + push ecx { Save ECX across call to CharUpper } + push eax { Push Char onto stack for CharUpper } + call CharUpper { Uppercase AL } + pop ecx { Restore saved register } + + mov [edi], al { Store first output character } + inc edi + + dec cl { One input character used } + jz @@Done { Was input string one char long? } + + mov ch, 03h { Output max 3 chars beyond first } + mov edx, offset SoundexTable { EDX => Soundex table } + xor eax, eax { Prepare for address calc } + xor bl, bl { BL will be used to store 'previous char' } + +@@Next: + mov al, [esi] { Get next char in AL } + inc esi + mov al, [edx+eax] { Get soundex code into AL } + or al, al { Is AL zero? } + jz @@NoStore { If yes, skip this char } + cmp bl, al { Is it the same as the previous stored char? } + je @@NoStore { If yes, skip this char } + mov [edi], al { Store char to Dest } + inc edi + dec ch { Decrement output counter } + jz @@Done { If zero, we're done } + mov bl, al { New previous character } + +@@NoStore: + dec cl { Decrement input counter } + jnz @@Next + +@@Done: + pop esi + pop ebx + pop edi +end; + +function MakeLetterSetS(const S : ShortString) : Longint; + {-Return a bit-mapped long storing the individual letters contained in S.} +register; +asm + push ebx { Save registers } + push esi + + mov esi, eax { ESI => string } + xor ecx, ecx { Zero ECX } + xor edx, edx { Zero EDX } + xor eax, eax { Zero EAX } + add cl, [esi] { CX = Length(S) } + jz @@Exit { Done if ECX is 0 } + inc esi + +@@Next: + mov al, [esi] { EAX has next char in S } + inc esi + + push ecx { Save registers } + push edx + push eax { Push Char onto stack for CharUpper } + call CharUpper + pop edx { Restore registers } + pop ecx + + sub eax, 'A' { Convert to bit number } + cmp eax, 'Z'-'A' { Was char in range 'A'..'Z'? } + ja @@Skip { Skip it if not } + + mov ebx, eax { Exchange EAX and ECX } + mov eax, ecx + mov ecx, ebx + ror edx, cl + or edx, 01h { Set appropriate bit } + rol edx, cl + mov ebx, eax { Exchange EAX and ECX } + mov eax, ecx + mov ecx, ebx + +@@Skip: + dec ecx + jnz @@Next { Get next character } + +@@Exit: + mov eax, edx { Move EDX to result } + pop esi { Restore registers } + pop ebx +end; + +procedure BMMakeTableS(const MatchString : ShortString; var BT : BTable); + {-Build a Boyer-Moore link table} +register; +asm + push edi { Save registers because they will be changed } + push esi + mov esi, eax { Move EAX to ESI } + push ebx + + xor eax, eax { Zero EAX } + xor ecx, ecx { Zero ECX } + mov cl, [esi] { ECX has length of MatchString } + inc esi + + mov ch, cl { Duplicate CL in CH } + mov eax, ecx { Fill each byte in EAX with length } + shl eax, 16 + or eax, ecx + mov edi, edx { Point to the table } + mov ecx, 64 { Fill table bytes with length } + rep stosd + cmp al, 1 { If length <= 1, we're done } + jbe @@MTDone + xor ebx, ebx { Zero EBX } + mov cl, al { Restore CL to length of string } + dec ecx + +@@MTNext: + mov al, [esi] { Load table with positions of letters } + mov bl, al { that exist in the search string } + inc esi + mov [edx+ebx], cl + dec cl + jnz @@MTNext + +@@MTDone: + pop ebx { Restore registers } + pop esi + pop edi +end; + +function BMSearchS(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : ShortString ; var Pos : Cardinal) : Boolean; assembler; + {-Use the Boyer-Moore search method to search a buffer for a string.} +register; +var + BufPtr : Pointer; +asm + push edi { Save registers since we will be changing } + push esi + push ebx + + mov BufPtr, eax { Copy Buffer to local variable and EDI } + mov edi, eax + mov ebx, ecx { Copy BT ptr to EBX } + mov ecx, edx { Length of buffer to ECX } + mov esi, MatchString { Set ESI to beginning of MatchString } + xor eax, eax { Zero EAX } + + mov dl, [esi] { Length of MatchString in EDX } + inc esi + and edx, 0FFh + + cmp dl, 1 { Check to see if we have a trivial case } + ja @@BMSInit { If Length(MatchString) > 1 do BM search } + jb @@BMSNotFound { If Length(MatchString) = 0 we're done } + + mov al,[esi] { If Length(MatchString) = 1 do a REPNE SCASB } + mov ebx, edi + repne scasb + jne @@BMSNotFound { No match during REP SCASB } + mov esi, Pos { Set position in Pos } + {dec edi} { Found, calculate position } + sub edi, ebx + mov eax, 1 { Set result to True } + mov [esi], edi + jmp @@BMSDone { We're done } + +@@BMSInit: + dec edx { Set up for BM Search } + add esi, edx { Set ESI to end of MatchString } + add ecx, edi { Set ECX to end of buffer } + add edi, edx { Set EDI to first check point } + std { Backward string ops } + mov dh, [esi] { Set DH to character we'll be looking for } + dec esi { Dec ESI in prep for BMSFound loop } + jmp @@BMSComp { Jump to first comparison } + +@@BMSNext: + mov al, [ebx+eax] { Look up skip distance from table } + add edi, eax { Skip EDI ahead to next check point } + +@@BMSComp: + cmp edi, ecx { Have we reached end of buffer? } + jae @@BMSNotFound { If so, we're done } + mov al, [edi] { Move character from buffer into AL for comparison } + cmp dh, al { Compare } + jne @@BMSNext { If not equal, go to next checkpoint } + + push ecx { Save ECX } + dec edi + xor ecx, ecx { Zero ECX } + mov cl, dl { Move Length(MatchString) to ECX } + repe cmpsb { Compare MatchString to buffer } + je @@BMSFound { If equal, string is found } + + mov al, dl { Move Length(MatchString) to AL } + sub al, cl { Calculate offset that string didn't match } + add esi, eax { Move ESI back to end of MatchString } + add edi, eax { Move EDI to pre-string compare location } + inc edi + mov al, dh { Move character back to AL } + pop ecx { Restore ECX } + jmp @@BMSNext { Do another compare } + +@@BMSFound: { EDI points to start of match } + mov edx, BufPtr { Move pointer to buffer into EDX } + mov esi, Pos + sub edi, edx { Calculate position of match } + mov eax, edi + inc eax + inc eax { Pos is one based } + mov [esi], eax { Set Pos to position of match } + mov eax, 1 { Set result to True } + pop ecx { Restore ESP } + jmp @@BMSDone + +@@BMSNotFound: + xor eax, eax { Set result to False } + +@@BMSDone: + cld { Restore direction flag } + pop ebx { Restore registers } + pop esi + pop edi +end; + +function BMSearchUCS(var Buffer; BufLength : Cardinal; var BT : BTable; + const MatchString : ShortString ; var Pos : Cardinal) : Boolean; assembler; + {-Use the Boyer-Moore search method to search a buffer for a string. This + search is not case sensitive.} +register; +var + BufPtr : Pointer; +asm + push edi { Save registers since we will be changing } + push esi + push ebx + + mov BufPtr, eax { Copy Buffer to local variable and ESI } + mov edi, eax + mov ebx, ecx { Copy BT ptr to EBX } + mov ecx, edx { Length of buffer to ECX } + mov esi, MatchString { Set ESI to beginning of MatchString } + xor eax, eax { Zero EAX } + + mov dl, byte ptr [esi] { Length of MatchString in EDX } + and edx, 0FFh { Clean up EDX } + inc esi { Set ESI to first character } + + or dl, dl { Check to see if we have a trivial case } + jz @@BMSNotFound { If Length(MatchString) = 0 we're done } + +@@BMSInit: + dec edx { Set up for BM Search } + add esi, edx { Set ESI to end of MatchString } + add ecx, edi { Set ECX to end of buffer } + add edi, edx { Set EDI to first check point } + std { Backward string ops } + mov dh, [esi] { Set DH to character we'll be looking for } + dec esi { Dec ESI in prep for BMSFound loop } + jmp @@BMSComp { Jump to first comparison } + +@@BMSNext: + mov al, [ebx+eax] { Look up skip distance from table } + add edi, eax { Skip EDI ahead to next check point } + +@@BMSComp: + cmp edi, ecx { Have we reached end of buffer? } + jae @@BMSNotFound { If so, we're done } + + push ebx { Save registers } + push ecx + push edx + mov al, [edi] { Move character from buffer into AL for comparison } + push eax { Push Char onto stack for CharUpper } + cld + call CharUpper + std + pop edx { Restore registers } + pop ecx + pop ebx + + cmp dh, al { Compare } + jne @@BMSNext { If not equal, go to next checkpoint } + + push ecx { Save ECX } + dec edi + xor ecx, ecx { Zero ECX } + mov cl, dl { Move Length(MatchString) to ECX } + jecxz @@BMSFound { If ECX is zero, string is found } + +@@StringComp: + xor eax, eax + mov al, [edi] { Get char from buffer } + dec edi { Dec buffer index } + + push ebx { Save registers } + push ecx + push edx + push eax { Push Char onto stack for CharUpper } + cld + call CharUpper + std + pop edx { Restore registers } + pop ecx + pop ebx + + mov ah, al { Move buffer char to AH } + mov al, [esi] { Get MatchString char } + dec esi + cmp ah, al { Compare } + loope @@StringComp { OK? Get next character } + je @@BMSFound { Matched! } + + xor ah, ah { Zero AH } + mov al, dl { Move Length(MatchString) to AL } + sub al, cl { Calculate offset that string didn't match } + add esi, eax { Move ESI back to end of MatchString } + add edi, eax { Move EDI to pre-string compare location } + inc edi + mov al, dh { Move character back to AL } + pop ecx { Restore ECX } + jmp @@BMSNext { Do another compare } + +@@BMSFound: { EDI points to start of match } + mov edx, BufPtr { Move pointer to buffer into EDX } + mov esi, Pos + sub edi, edx { Calculate position of match } + mov eax, edi + inc eax + inc eax { Pos is one based } + mov [esi], eax { Set Pos to position of match } + mov eax, 1 { Set result to True } + pop ecx { Restore ESP } + jmp @@BMSDone + +@@BMSNotFound: + xor eax, eax { Set result to False } + +@@BMSDone: + cld { Restore direction flag } + pop ebx { Restore registers } + pop esi + pop edi +end; + + {--------------- DOS pathname parsing -----------------} + +function DefaultExtensionS(const Name, Ext : ShortString) : ShortString; + {-Return a file name with a default extension attached.} +var + DotPos : Cardinal; +begin + if HasExtensionS(Name, DotPos) then + Result := Name + else if Name = '' then + Result := '' + else + Result := Name + '.' + Ext; +end; + +function ForceExtensionS(const Name, Ext : ShortString) : ShortString; + {-Force the specified extension onto the file name.} +var + DotPos : Cardinal; +begin + if HasExtensionS(Name, DotPos) then + Result := Copy(Name, 1, DotPos) + Ext + else if Name = '' then + Result := '' + else + Result := Name + '.' + Ext; +end; + +function JustFilenameS(const PathName : ShortString) : ShortString; + {-Return just the filename and extension of a pathname.} +var + I : Longint; +begin + Result := ''; + if PathName = '' then + Exit; + I := Succ(Length(PathName)); + repeat + Dec(I); + until (I = 0) or (PathName[I] in DosDelimSet); {!!.01} + Result := Copy(PathName, Succ(I), StMaxFileLen); +end; + +function JustNameS(const PathName : ShortString) : ShortString; + {-Return just the filename (no extension, path, or drive) of a pathname.} +var + DotPos : Cardinal; +begin + Result := JustFileNameS(PathName); + if HasExtensionS(Result, DotPos) then + Result := Copy(Result, 1, DotPos-1); +end; + +function JustExtensionS(const Name : ShortString) : ShortString; + {-Return just the extension of a pathname.} +var + DotPos : Cardinal; +begin + if HasExtensionS(Name, DotPos) then + Result := Copy(Name, Succ(DotPos), StMaxFileLen) + else + Result := ''; +end; + +function JustPathnameS(const PathName : ShortString) : ShortString; + {-Return just the drive and directory portion of a pathname.} +var + I : Longint; +begin + I := Succ(Length(PathName)); + repeat + Dec(I); + until (I = 0) or (PathName[I] in DosDelimSet); {!!.01} + + if I = 0 then + {Had no drive or directory name} + Result [0] := #0 + else if I = 1 then + {Either the root directory of default drive or invalid pathname} + Result := PathName[1] + else if (PathName[I] = '\') then begin + if PathName[Pred(I)] = ':' then + {Root directory of a drive, leave trailing backslash} + Result := Copy(PathName, 1, I) + else + {Subdirectory, remove the trailing backslash} + Result := Copy(PathName, 1, Pred(I)); + end else + {Either the default directory of a drive or invalid pathname} + Result := Copy(PathName, 1, I); +end; + +function AddBackSlashS(const DirName : ShortString) : ShortString; + {-Add a default backslash to a directory name} +begin + Result := DirName; + if (Length(Result) = 0) then + Exit; + if ((Length(Result) = 2) and (Result[2] = ':')) or + ((Length(Result) > 2) and (Result[Length(Result)] <> '\')) then + Result := Result + '\'; +end; + +function CleanFileNameS(const FileName : ShortString) : ShortString; + {-Return filename with at most 8 chars of name and 3 of extension} +var + DotPos : Cardinal; + NameLen : Cardinal; +begin + if HasExtensionS(FileName, DotPos) then begin + {Take the first 8 chars of name and first 3 chars of extension} + NameLen := Pred(DotPos); + if NameLen > 8 then + NameLen := 8; + Result := Copy(FileName, 1, NameLen)+Copy(FileName, DotPos, 4); + end else + {Take the first 8 chars of name} + Result := Copy(FileName, 1, 8); +end; + +function CleanPathNameS(const PathName : ShortString) : ShortString; + {-Return a pathname cleaned up as DOS does it.} +var + I : Longint; + S : ShortString; +begin + Result[0] := #0; + S := PathName; + + I := Succ(Length(S)); + repeat + dec(I); + if I > 2 then + if (S[I] = '\') and (S[I-1] = '\') then + if (S[I-2] <> ':') then + Delete(S, I, 1); + until I <= 0; + + I := Succ(Length(S)); + repeat + {Get the next directory or drive portion of pathname} + repeat + Dec(I); + until (I = 0) or (S[I] in DosDelimSet); {!!.02} + + {Clean it up and prepend it to output string} + Result := CleanFileNameS(Copy(S, Succ(I), StMaxFileLen)) + Result; + if I > 0 then begin + Result := S[I] + Result; + Delete(S, I, 255); + end; + until I <= 0; + +end; + +function HasExtensionS(const Name : ShortString; var DotPos : Cardinal) : Boolean; + {-Determine if a pathname contains an extension and, if so, return the + position of the dot in front of the extension.} +var + I : Cardinal; +begin + DotPos := 0; + for I := Length(Name) downto 1 do + if (Name[I] = '.') and (DotPos = 0) then + DotPos := I; + Result := (DotPos > 0) + {and (Pos('\', Copy(Name, Succ(DotPos), MaxFileLen)) = 0);} + and not CharExistsS(Copy(Name, Succ(DotPos), StMaxFileLen), '\'); +end; + + {------------------ Formatting routines --------------------} + + +function CommaizeChS(L : Longint; Ch : AnsiChar) : ShortString; + {-Convert a long integer to a string with Ch in comma positions} +var + NumCommas, I, Len : Cardinal; + Neg : Boolean; +begin + if L < 0 then begin + Neg := True; + L := Abs(L); + end else + Neg := False; + Result := Long2StrS(L); + Len := Length(Result); + NumCommas := (Len - 1) div 3; + for I := 1 to NumCommas do + System.Insert(Ch, Result, Len-(I * 3)+1); + if Neg then + System.Insert('-', Result, 1); +end; + +function CommaizeS(L : LongInt) : ShortString; + {-Convert a long integer to a string with commas} +begin + Result := CommaizeChS(L, ','); +end; + +function FormPrimS(const Mask : ShortString; R : TstFloat; const LtCurr, + RtCurr : ShortString; Sep, DecPt : AnsiChar; + AssumeDP : Boolean) : ShortString; + {-Returns a formatted string with digits from R merged into the Mask} +const + Blank = 0; + Asterisk = 1; + Zero = 2; +const +{$IFOPT N+} + MaxPlaces = 18; +{$ELSE} + MaxPlaces = 11; +{$ENDIF} + FormChars : string[8] = '#@*$-+,.'; + PlusArray : array[Boolean] of AnsiChar = ('+', '-'); + MinusArray : array[Boolean] of AnsiChar = (' ', '-'); + FillArray : array[Blank..Zero] of AnsiChar = (' ', '*', '0'); +var + S : ShortString; {temporary string} + Filler : Integer; {char for unused digit slots: ' ', '*', '0'} + WontFit, {true if number won't fit in the mask} + AddMinus, {true if minus sign needs to be added} + Dollar, {true if floating dollar sign is desired} + Negative : Boolean; {true if B is negative} + StartF, {starting point of the numeric field} + EndF : Word; {end of numeric field} + RtChars, {# of chars to add to right} + LtChars, {# of chars to add to left} + DotPos, {position of '.' in Mask} + Digits, {total # of digits} + Places, {# of digits after the '.'} + Blanks, {# of blanks returned by Str} + FirstDigit, {pos. of first digit returned by Str} + Extras, {# of extra digits needed for special cases} + DigitPtr : Byte; {pointer into temporary string of digits} + I : Word; +label + EndFound, + RedoCase, + Done; +begin + {assume decimal point at end?} + Result := Mask; + if (not AssumeDP) and (not CharExistsS(Result, '.')) then + AssumeDP := true; + if AssumeDP and (Result <> '') and (Length(Result) < 255) then begin + Inc(Result[0]); + Result[Length(Result)] := '.'; + end; + + RtChars := 0; + LtChars := 0; + + {check for empty string} + if Length(Result) = 0 then + goto Done; + + {initialize variables} + Filler := Blank; + DotPos := 0; + Places := 0; + Digits := 0; + Dollar := False; + AddMinus := True; + StartF := 1; + + {store the sign of the real and make it positive} + Negative := (R < 0); + R := Abs(R); + + {strip and count c's} + for I := Length(Result) downto 1 do begin + if Result[I] = 'C' then begin + Inc(RtChars); + System.Delete(Result, I, 1); + end else if Result[I] = 'c' then begin + Inc(LtChars); + System.Delete(Result, I, 1); + end; + end; + + {find the starting point for the field} + while (StartF <= Length(Result)) and + not CharExistsS(FormChars, Result[StartF]) do + Inc(StartF); + if StartF > Length(Result) then + goto Done; + + {find the end point for the field} + EndF := StartF; + for I := StartF to Length(Result) do begin + EndF := I; + case Result[I] of + '*' : Filler := Asterisk; + '@' : Filler := Zero; + '$' : Dollar := True; + '-', + '+' : AddMinus := False; + '#' : {ignore} ; + ',', + '.' : DotPos := I; + else + goto EndFound; + end; + {Inc(EndF);} + end; + + {if we get here at all, the last char was part of the field} + Inc(EndF); + +EndFound: + {if we jumped to here instead, it wasn't} + Dec(EndF); + + {disallow Dollar if Filler is Zero} + if Filler = Zero then + Dollar := False; + + {we need an extra slot if Dollar is True} + Extras := Ord(Dollar); + + {get total # of digits and # after the decimal point} + for I := StartF to EndF do + case Result[I] of + '#', '@', + '*', '$' : + begin + Inc(Digits); + if (I > DotPos) and (DotPos <> 0) then + Inc(Places); + end; + end; + + {need one more 'digit' if Places > 0} + Inc(Digits, Ord(Places > 0)); + + {also need an extra blank if (1) Negative is true, and (2) Filler is Blank, + and (3) AddMinus is true} + if Negative and AddMinus and (Filler = Blank) then + Inc(Extras) + else + AddMinus := False; + + {translate the real to a string} + Str(R:Digits:Places, S); + + {add zeros that Str may have left out} + if Places > MaxPlaces then begin + FillChar(S[Length(S)+1], Places-MaxPlaces, '0'); + inc(S[0], Places-MaxPlaces); + while (Length(S) > Digits) and (S[1] = ' ') do + System.Delete(S, 1, 1); + end; + + {count number of initial blanks} + Blanks := 1; + while S[Blanks] = ' ' do + Inc(Blanks); + FirstDigit := Blanks; + Dec(Blanks); + + {the number won't fit if (a) S is longer than Digits or (b) the number of + initial blanks is less than Extras} + WontFit := (Length(S) > Digits) or (Blanks < Extras); + + {if it won't fit, fill decimal slots with '*'} + if WontFit then begin + for I := StartF to EndF do + case Result[I] of + '#', '@', '*', '$' : Result[I] := '*'; + '+' : Result[I] := PlusArray[Negative]; + '-' : Result[I] := MinusArray[Negative]; + end; + goto Done; + end; + + {fill initial blanks in S with Filler; insert floating dollar sign} + if Blanks > 0 then begin + FillChar(S[1], Blanks, FillArray[Filler]); + + {put floating dollar sign in last blank slot if necessary} + if Dollar then begin + S[Blanks] := LtCurr[1]; + Dec(Blanks); + end; + + {insert a minus sign if necessary} + if AddMinus then + S[Blanks] := '-'; + end; + + {put in the digits / signs} + DigitPtr := Length(S); + for I := EndF downto StartF do begin +RedoCase: + case Result[I] of + '#', '@', '*', '$' : + if DigitPtr <> 0 then begin + Result[I] := S[DigitPtr]; + Dec(DigitPtr); + if (DigitPtr <> 0) and (S[DigitPtr] = '.') then {!!.01} + Dec(DigitPtr); + end + else + Result[I] := FillArray[Filler]; + ',' : + begin + Result[I] := Sep; + if (I < DotPos) and (DigitPtr < FirstDigit) then begin + Result[I] := '#'; + goto RedoCase; + end; + end; + '.' : + begin + Result[I] := DecPt; + if (I < DotPos) and (DigitPtr < FirstDigit) then begin + Result[I] := '#'; + goto RedoCase; + end; + end; + '+' : Result[I] := PlusArray[Negative]; + '-' : Result[I] := MinusArray[Negative]; + end; + end; + +Done: + if AssumeDP then + Dec(Result[0]); + if RtChars > 0 then begin + S := RtCurr; + if Byte(S[0]) > RtChars then + S[0] := AnsiChar(RtChars) + else + S := LeftPadS(S, RtChars); + Result := Result + S; + end; + if LtChars > 0 then begin + S := LtCurr; + if Byte(S[0]) > LtChars then + S[0] := AnsiChar(LtChars) + else + S := PadS(S, LtChars); + Result := S + Result; + end; +end; + +function FloatFormS(const Mask : ShortString ; R : TstFloat ; const LtCurr, + RtCurr : ShortString ; Sep, DecPt : AnsiChar) : ShortString; + {-Return a formatted string with digits from R merged into mask.} +begin + Result := FormPrimS(Mask, R, LtCurr, RtCurr, Sep, DecPt, False); +end; + +function LongIntFormS(const Mask : ShortString ; L : LongInt ; const LtCurr, + RtCurr : ShortString ; Sep : AnsiChar) : ShortString; + {-Return a formatted string with digits from L merged into mask.} +begin + Result := FormPrimS(Mask, L, LtCurr, RtCurr, Sep, '.', True); +end; + +function StrChPosS(const P : String; C : Char; var Pos : Cardinal) : Boolean; +var + I: Integer; +{-Return the position of a specified character within a string.} +begin + Result := False; + for I := 1 to Length(P) do + begin + if P[I] = C then + begin + Result := True; + Pos := I; + Break; + end; + end; +end; + +function StrChPosS(const P : ShortString; C : AnsiChar; var Pos : Cardinal) : Boolean; + {-Return the position of a specified character within a string.} +asm + push ebx { Save registers } + push edi + + xor edi, edi { Zero counter } + xor ebx, ebx + add bl, [eax] { Get input length } + jz @@NotFound + inc eax + +@@Loop: + inc edi { Increment counter } + cmp [eax], dl { Did we find it? } + jz @@Found + inc eax { Increment pointer } + + cmp edi, ebx { End of string? } + jnz @@Loop { If not, loop } + +@@NotFound: + xor eax, eax { Not found, zero EAX for False } + mov [ecx], eax + jmp @@Done + +@@Found: + mov [ecx], edi { Set Pos } + mov eax, 1 { Set EAX to True } + +@@Done: + pop edi { Restore registers } + pop ebx +end; + +function StrStPosS(const P, S : ShortString; var Pos : Cardinal) : Boolean; + {-Return the position of a specified substring within a string.} +begin + Pos := System.Pos(S, P); + Result := Pos <> 0; +end; + +function StrStCopyS(const S : ShortString; Pos, Count : Cardinal) : ShortString; + {-Copy characters at a specified position in a string.} +begin + Result := System.Copy(S, Pos, Count); +end; + +function StrChInsertS(const S : ShortString; C : AnsiChar; Pos : Cardinal) : ShortString; + {-Insert a character into a string at a specified position.} +var + Temp : string[2]; +begin + Temp[0] := #1; + Temp[1] := C; + Result := S; + System.Insert(Temp, Result, Pos); +end; + +function StrStInsertS(const S1, S2 : ShortString; Pos : Cardinal) : ShortString; + {-Insert a string into another string at a specified position.} +begin + Result := S1; + System.Insert(S2, Result, Pos); +end; + +function StrChDeleteS(const S : ShortString; Pos : Cardinal) : ShortString; + {-Delete the character at a specified position in a string.} +begin + Result := S; + System.Delete(Result, Pos, 1); +end; + +function StrStDeleteS(const S : ShortString; Pos, Count : Cardinal) : ShortString; + {-Delete characters at a specified position in a string.} +begin + Result := S; + System.Delete(Result, Pos, Count); +end; + +{----------------------------- NEW FUNCTIONS (3.00) -------------------------} + +function CopyLeftS(const S : ShortString; Len : Cardinal) : ShortString; + {-Return the left Len characters of a string} +begin + if (Len < 1) or (S = '') then + Result := '' + else + Result := Copy(S, 1, Len); +end; + + + +function CopyMidS(const S : ShortString; First, Len : Cardinal) : ShortString; + {-Return the mid part of a string} +begin + if (First > Length(S)) or (Len < 1) or (S = '') then + Result := '' + else + Result := Copy(S, First, Len); +end; + + + +function CopyRightS(const S : ShortString; First : Cardinal) : ShortString; + {-Return the right Len characters of a string} +begin + if (First > Length(S)) or (First < 1) or (S = '') then + Result := '' + else + Result := Copy(S, First, Length(S)); +end; + +function CopyRightAbsS(const S : ShortString; NumChars : Cardinal) : ShortString; + {-Return NumChar characters starting from end} +begin + if (Length(S) > NumChars) then + Result := Copy(S, (Length(S) - NumChars)+1, NumChars) + else + Result := S; +end; + + +function CopyFromNthWordS(const S, WordDelims : ShortString; + const AWord : ShortString; N : Cardinal; {!!.02} + var SubString : ShortString) : Boolean; +var + P : Cardinal; +begin + if (WordPosS(S, WordDelims, AWord, N, P)) then begin + SubString := Copy(S, P, Length(S)); + Result := True; + end else begin + SubString := ''; + Result := False; + end; +end; + + + +function DeleteFromNthWordS(const S, WordDelims : ShortString; + AWord : ShortString; N : Cardinal; + var SubString : ShortString) : Boolean; +var + P : Cardinal; +begin + if (WordPosS(S, WordDelims, AWord, N, P)) then begin + Result := True; + SubString := Copy(S, 1, P-1); + end else begin + Result := False; + SubString := ''; + end; +end; + + + +function CopyFromToWordS(const S, WordDelims, Word1, Word2 : ShortString; + N1, N2 : Cardinal; + var SubString : ShortString) : Boolean; +var + P1, + P2 : Cardinal; +begin + if (WordPosS(S, WordDelims, Word1, N1, P1)) then begin + if (WordPosS(S, WordDelims, Word2, N2, P2)) then begin + Dec(P2); + if (P2 > P1) then begin + Result := True; + SubString := Copy(S, P1, P2-P1); + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; +end; + + + +function DeleteFromToWordS(const S, WordDelims, Word1, Word2 : ShortString; + N1, N2 : Cardinal; + var SubString : ShortString) : Boolean; +var + P1, + P2 : Cardinal; +begin + SubString := S; + if (WordPosS(S, WordDelims, Word1, N1, P1)) then begin + if (WordPosS(S, WordDelims, Word2, N2, P2)) then begin + Dec(P2); + if (P2 > P1) then begin + Result := True; + System.Delete(SubString, P1, P2-P1+1); + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; + end else begin + Result := False; + SubString := ''; + end; +end; + + + +function CopyWithinS(const S, Delimiter : ShortString; + Strip : Boolean) : ShortString; +var + P1, + P2 : Cardinal; + TmpStr : ShortString; +begin + if (S = '') or (Delimiter = '') or (Pos(Delimiter, S) = 0) then + Result := '' + else begin + if (StrStPosS(S, Delimiter, P1)) then begin + TmpStr := Copy(S, P1 + Length(Delimiter), Length(S)); + if StrStPosS(TmpStr, Delimiter, P2) then begin + Result := Copy(TmpStr, 1, P2-1); + if (not Strip) then + Result := Delimiter + Result + Delimiter; + end else begin + Result := TmpStr; + if (not Strip) then + Result := Delimiter + Result; + end; + end; + end; +end; + + + +function DeleteWithinS(const S, Delimiter : ShortString) : ShortString; +var + P1, + P2 : Cardinal; + TmpStr : ShortString; +begin + if (S = '') or (Delimiter = '') or (Pos(Delimiter, S) = 0) then + Result := '' + else begin + if (StrStPosS(S, Delimiter, P1)) then begin + TmpStr := Copy(S, P1 + Length(Delimiter), Length(S)); + if (Pos(Delimiter, TmpStr) = 0) then + Result := Copy(S, 1, P1-1) + else begin + if (StrStPosS(TmpStr, Delimiter, P2)) then begin + Result := S; + P2 := P2 + (2*Length(Delimiter)); + System.Delete(Result, P1, P2); + end; + end; + end; + end; +end; + + + +function ReplaceWordS(const S, WordDelims, OldWord, NewWord : ShortString; + N : Cardinal; + var Replacements : Cardinal) : ShortString; +var + I, + C, + P1 : Cardinal; +begin + if (S = '') or (WordDelims = '') or (OldWord = '') or + (Pos(OldWord, S) = 0) then begin + Result := S; + Replacements := 0; + end else begin + if (WordPosS(S, WordDelims, OldWord, N, P1)) then begin + Result := S; + System.Delete(Result, P1, Length(OldWord)); + C := 0; + for I := 1 to Replacements do begin + if ((Length(NewWord) + Length(Result)) <= 255) then begin + Inc(C); + System.Insert(NewWord, Result, P1); + Inc(P1, Length(NewWord) + 1); + end else begin + Replacements := C; + Exit; + end; + end; + end else begin + Result := S; + Replacements := 0; + end; + end; +end; + + +function ReplaceWordAllS(const S, WordDelims, OldWord, NewWord : ShortString; + var Replacements : Cardinal) : ShortString; +var + I, + C, + P1 : Cardinal; +begin + if (S = '') or (WordDelims = '') or (OldWord = '') or + (Pos(OldWord, S) = 0) then begin + Result := S; + Replacements := 0; + end else begin + Result := S; + C := 0; + while (WordPosS(Result, WordDelims, OldWord, 1, P1)) do begin + System.Delete(Result, P1, Length(OldWord)); + for I := 1 to Replacements do begin + if ((Length(NewWord) + Length(Result)) <= 255) then begin + Inc(C); + System.Insert(NewWord, Result, P1); + end else begin + Replacements := C; + Exit; + end; + end; + end; + Replacements := C; + end; +end; + + +function ReplaceStringS(const S, OldString, NewString : ShortString; + N : Cardinal; + var Replacements : Cardinal) : ShortString; +var + I, + C, + P1 : Cardinal; + TmpStr : ShortString; +begin + if (S = '') or (OldString = '') or (Pos(OldString, S) = 0) then begin + Result := S; + Replacements := 0; + Exit; + end; + TmpStr := S; + + I := 1; + P1 := Pos(OldString, TmpStr); + C := P1; + while (I < N) and (C < Length(TmpStr)) do begin + Inc(I); + System.Delete(TmpStr, 1, P1 + Length(OldString)); + Inc(C, P1 + Length(OldString)); + end; + Result := S; + System.Delete(Result, C, Length(OldString)); + + C := 0; + for I := 1 to Replacements do begin + if ((Length(NewString) + Length(Result)) <= 255) then begin + Inc(C); + System.Insert(NewString, Result, P1); + Inc(P1, Length(NewString) + 1); + end else begin + Replacements := C; + Exit; + end; + end; +end; + + +function ReplaceStringAllS(const S, OldString, NewString : ShortString; + var Replacements : Cardinal) : ShortString; +var + I, + C, + P1 : Cardinal; + Tmp: String; +begin + Result := S; + if (S = '') or (OldString = '') or (Pos(OldString, S) = 0) then + Replacements := 0 + else begin + Tmp := S; + P1 := Pos(OldString, S); + if (P1 > 0) then begin + Result := Copy(Tmp, 1, P1-1); + C := 0; + while (P1 > 0) do begin + for I := 1 to Replacements do begin + Inc(C); + Result := Result + NewString; + end; + Tmp := Copy(Tmp, P1+Length(OldString), MaxInt); + P1 := Pos(OldString, Tmp); + if (P1 > 0) then begin + Result := Result + Copy(Tmp, 1, P1-1); + {Tmp := Copy(Tmp, P1, MaxInt)}; + end else + Result := Result + Tmp; + end; + Replacements := C; + end else begin + Result := S; + Replacements := 0; + end; + end; +end; + +function LastWordS(const S, WordDelims, AWord : ShortString; + var Position : Cardinal) : Boolean; +var + TmpStr : ShortString; + I : Cardinal; +begin + if (S = '') or (WordDelims = '') or + (AWord = '') or (Pos(AWord, S) = 0) then begin + Result := False; + Position := 0; + Exit; + end; + + TmpStr := S; + I := Length(TmpStr); + while (Pos(TmpStr[I], WordDelims) > 0) do begin + System.Delete(TmpStr, I, 1); + I := Length(TmpStr); + end; + + Position := Length(TmpStr); + repeat + while (Pos(TmpStr[Position], WordDelims) = 0) and (Position > 1) do + Dec(Position); + if (Copy(TmpStr, Position + 1, Length(AWord)) = AWord) then begin + Inc(Position); + Result := True; + Exit; + end; + System.Delete(TmpStr, Position, Length(TmpStr)); + Position := Length(TmpStr); + until (Length(TmpStr) = 0); + Result := False; + Position := 0; +end; + + + +function LastWordAbsS(const S, WordDelims : ShortString; + var Position : Cardinal) : Boolean; +begin + if (S = '') or (WordDelims = '') then begin + Result := False; + Position := 0; + Exit; + end; + +{find first non-delimiter character, if any. If not a "one-word wonder"} + Position := Length(S); + while (Position > 0) and (Pos(S[Position], WordDelims) > 0) do + Dec(Position); + + if (Position = 0) then begin + Result := True; + Position := 1; + Exit; + end; + +{find next delimiter character} + while (Position > 0) and (Pos(S[Position], WordDelims) = 0) do + Dec(Position); + Inc(Position); + Result := True; +end; + + + +function LastStringS(const S, AString : ShortString; + var Position : Cardinal) : Boolean; +var + TmpStr : ShortString; + I, C : Cardinal; +begin + if (S = '') or (AString = '') or (Pos(AString, S) = 0) then begin + Result := False; + Position := 0; + Exit; + end; + + TmpStr := S; + C := 0; + I := Pos(AString, TmpStr); + while (I > 0) do begin + Inc(C, I + Length(AString)); + System.Delete(TmpStr, 1, I + Length(AString)); + I := Pos(AString, TmpStr); + end; +{Go back the length of AString since the while loop deletes the last instance} + Dec(C, Length(AString)); + Position := C; + Result := True; +end; + + + +function KeepCharsS(const S, Chars : ShortString) : ShortString; +var + FromInx : Cardinal; + ToInx : Cardinal; +begin + {if either the input string or the list of acceptable chars is empty + the destination string will also be empty} + if (S = '') or (Chars = '') then begin + Result := ''; + Exit; + end; + + {set the maximum length of the result string (it could be less than + this, of course} + Result[0] := AnsiChar(length(S)); + + {start off the to index} + ToInx := 0; + + {in a loop, copy over the chars that match the list} + for FromInx := 1 to length(S) do + if CharExistsS(Chars, S[FromInx]) then begin + inc(ToInx); + Result[ToInx] := S[FromInx]; + end; + + {make sure that the length of the result string is correct} + Result[0] := AnsiChar(ToInx); +end; + + + +function RepeatStringS(const RepeatString : ShortString; + var Repetitions : Cardinal; + MaxLen : Cardinal) : ShortString; +var + i : Cardinal; + Len : Cardinal; + ActualReps : Cardinal; +begin + Result := ''; + if (MaxLen <> 0) and + (Repetitions <> 0) and + (RepeatString <> '') then begin + if (MaxLen > 255) then + MaxLen := 255; + Len := length(RepeatString); + ActualReps := MaxLen div Len; + if (ActualReps > Repetitions) then + ActualReps := Repetitions + else + Repetitions := ActualReps; + if (ActualReps > 0) then begin + Result[0] := AnsiChar(ActualReps * Len); + for i := 0 to pred(ActualReps) do + Move(RepeatString[1], Result[i * Len + 1], Len); + end; + end; +end; + + + +function TrimCharsS(const S, Chars : ShortString) : ShortString; +begin + Result := RightTrimCharsS(S, Chars); + Result := LeftTrimCharsS(Result, Chars); +end; + + + +function RightTrimCharsS(const S, Chars : ShortString) : ShortString; +var + CutOff : integer; +begin + CutOff := length(S); + while (CutOff > 0) do begin + if not CharExistsS(Chars, S[CutOff]) then + Break; + dec(CutOff); + end; + if (CutOff = 0) then + Result := '' + else + Result := Copy(S, 1, CutOff); +end; + + + +function LeftTrimCharsS(const S, Chars : ShortString) : ShortString; +var + CutOff : integer; + LenS : integer; +begin + LenS := length(S); + CutOff := 1; + while (CutOff <= LenS) do begin + if not CharExistsS(Chars, S[CutOff]) then + Break; + inc(CutOff); + end; + if (CutOff > LenS) then + Result := '' + else + Result := Copy(S, CutOff, LenS - CutOff + 1); +end; + + + +function ExtractTokensS(const S, Delims : ShortString; + QuoteChar : AnsiChar; + AllowNulls : Boolean; + Tokens : TStrings) : Cardinal; +var + State : (ScanStart, + ScanQuotedToken, + ScanQuotedTokenEnd, + ScanNormalToken, + ScanNormalTokenWithQuote); + CurChar : AnsiChar; + TokenStart : integer; + Inx : integer; +begin + {Notes: this routine implements the following state machine + start ----> ScanStart + ScanStart-----quote----->ScanQuotedToken + ScanStart-----delim----->ScanStart (1) + ScanStart-----other----->ScanNormalToken + ScanQuotedToken-----quote----->ScanQuotedTokenEnd + ScanQuotedToken-----other----->ScanQuotedToken + ScanQuotedTokenEnd-----quote----->ScanNormalTokenWithQuote + ScanQuotedTokenEnd-----delim----->ScanStart (2) + ScanQuotedTokenEnd-----other----->ScanNormalToken + ScanNormalToken-----quote----->ScanNormalTokenWithQuote + ScanNormalToken-----delim----->ScanStart (3) + ScanNormalToken-----other----->ScanNormalToken + ScanNormalTokenWithQuote-----quote----->ScanNormalTokenWithQuote + ScanNormalTokenWithQuote-----other----->ScanNormalToken + + (1) output a null token if allowed + (2) output a token, stripping quotes (if the dequoted token is + empty, output a null token if allowed) + (3) output a token; no quote stripping + + If the quote character is #0, it's taken to mean that the routine + should not check for quoted substrings.} + + {clear the tokens string list, set the return value to zero} + Tokens.Clear; + Result := 0; + + {if the input string is empty or the delimiter list is empty or + the quote character is found in the delimiter list, return zero + tokens found} + if (S = '') or + (Delims = '') or + CharExistsS(Delims, QuoteChar) then + Exit; + + {start off in the normal scanning state} + State := ScanStart; + + {the first token starts at position 1} + TokenStart := 1; + + {read through the entire string} + for Inx := 1 to length(S) do begin + + {get the current character} + CurChar := S[Inx]; + + {process the character according to the current state} + case State of + ScanStart : + begin + {if the current char is the quote character, switch states} + if (QuoteChar <> #0) and (CurChar = QuoteChar) then + State := ScanQuotedToken + + {if the current char is a delimiter, output a null token} + else if CharExistsS(Delims, CurChar) then begin + + {if allowed to, output a null token} + if AllowNulls then begin + Tokens.Add(''); + inc(Result); + end; + + {set the start of the next token to be one character after + this delimiter} + TokenStart := succ(Inx); + end + + {otherwise, the current char is starting a normal token, so + switch states} + else + State := ScanNormalToken + end; + + ScanQuotedToken : + begin + {if the current char is the quote character, switch states} + if (CurChar = QuoteChar) then + State := ScanQuotedTokenEnd + end; + + ScanQuotedTokenEnd : + begin + {if the current char is the quote character, we have a token + consisting of two (or more) quoted substrings, so switch + states} + if (CurChar = QuoteChar) then + State := ScanNormalTokenWithQuote + + {if the current char is a delimiter, output the token + without the quotes} + else if CharExistsS(Delims, CurChar) then begin + + {if the token is empty without the quotes, output a null + token only if allowed to} + if ((Inx - TokenStart) = 2) then begin + if AllowNulls then begin + Tokens.Add(''); + inc(Result); + end + end + + {else output the token without the quotes} + else begin + Tokens.Add(Copy(S, succ(TokenStart), Inx - TokenStart - 2)); + inc(Result); + end; + + {set the start of the next token to be one character after + this delimiter} + TokenStart := succ(Inx); + + {switch states back to the start state} + State := ScanStart; + end + + {otherwise it's a (complex) normal token, so switch states} + else + State := ScanNormalToken + end; + + ScanNormalToken : + begin + {if the current char is the quote character, we have a + complex token with at least one quoted substring, so switch + states} + if (QuoteChar <> #0) and (CurChar = QuoteChar) then + State := ScanNormalTokenWithQuote + + {if the current char is a delimiter, output the token} + else if CharExistsS(Delims, CurChar) then begin + Tokens.Add(Copy(S, TokenStart, Inx - TokenStart)); + inc(Result); + + {set the start of the next token to be one character after + this delimiter} + TokenStart := succ(Inx); + + {switch states back to the start state} + State := ScanStart; + end; + end; + + ScanNormalTokenWithQuote : + begin + {if the current char is the quote character, switch states + back to scanning a normal token} + if (CurChar = QuoteChar) then + State := ScanNormalToken; + end; + + end; + end; + + {we need to process the (possible) final token: first assume that + the current character index is just beyond the end of the string} + Inx := succ(length(S)); + + {if we are in the scanning quoted token state, we've read an opening + quote, but no closing one; increment the token start value} + if (State = ScanQuotedToken) then + inc(TokenStart) + + {if we've finished scanning a quoted token, we've read both quotes; + increment the token start value, and decrement the current index} + else if (State = ScanQuotedTokenEnd) then begin + inc(TokenStart); + dec(Inx); + end; + + {if the final token is not empty, output the token} + if (TokenStart < Inx) then begin + Tokens.Add(Copy(S, TokenStart, Inx - TokenStart)); + inc(Result); + end + {otherwise the final token is empty, so output a null token if + allowed to} + else if AllowNulls then begin + Tokens.Add(''); + inc(Result); + end; +end; + + + +function ContainsOnlyS(const S, Chars : ShortString; + var BadPos : Cardinal) : Boolean; +var + I : Cardinal; +begin + if (S = '') then begin + Result := False; + BadPos := 0; + end else begin + for I := 1 to Length(S) do begin + if (not CharExistsS(Chars, S[I])) then begin + BadPos := I; + Result := False; + Exit; + end; + end; + Result := True; + BadPos := 0; + end; +end; + + + +function ContainsOtherThanS(const S, Chars : ShortString; + var BadPos : Cardinal) : Boolean; +var + I : Cardinal; +begin + if (S = '') then begin + Result := False; + BadPos := 0; + end else begin + for I := 1 to Length(S) do begin + if (CharExistsS(Chars, S[I])) then begin + BadPos := I; + Result := True; + Exit; + end; + end; + Result := False; + BadPos := 0; + end; +end; + + + +function IsChAlphaS(C : Char) : Boolean; + {-Returns true if Ch is an alpha} +begin + {$IFDEF FPC} + Result := C in ['a'..'z', 'A'..'Z']; + {$ELSE} + Result := Windows.IsCharAlpha(C); + {$ENDIF} +end; + + + +function IsChNumericS(C : AnsiChar; const Numbers : ShortString) : Boolean; + {-Returns true if Ch in numeric set} +begin + Result := CharExistsS(Numbers, C); +end; + + +function IsChAlphaNumericS(C : Char; const Numbers : ShortString) : Boolean; + {-Returns true if Ch is an alpha or numeric} +begin + {$IFDEF FPC} + Result := IsChAlphaS(C) or CharExistsS(Numbers, C); + {$ELSE} + Result := Windows.IsCharAlpha(C) or CharExistsS(Numbers, C); + {$ENDIF} +end; + + + +function IsStrAlphaS(const S : string) : Boolean; + {-Returns true if all characters in string are an alpha} +var + I : Cardinal; +begin + Result := false; + if (length(S) > 0) then begin + for I := 1 to Length(S) do + {$IFDEF FPC} + if not IsChAlphaS(S[I]) then + Exit; + {$ELSE} + if not Windows.IsCharAlpha(S[I]) then + Exit; + {$ENDIF} + Result := true; + end; +end; + + + +function IsStrNumericS(const S, Numbers : ShortString) : Boolean; + {-Returns true if all characters in string are in numeric set} +var + i : Cardinal; +begin + Result := false; + if (length(S) > 0) then begin + for i := 1 to Length(S) do + if not CharExistsS(Numbers, S[i]) then + Exit; + Result := true; + end; +end; + + +function IsStrAlphaNumericS(const S, Numbers : String) : Boolean; + {-Returns true if all characters in string are alpha or numeric} +var + i : Cardinal; +begin + Result := false; + if (length(S) > 0) then begin + for I := 1 to Length(S) do + {$IFDEF FPC} + if not IsChAlphaNumericS(S[i], Numbers) then + Exit; + {$ELSE} + if (not Windows.IsCharAlpha(S[i])) and + (not CharExistsS(Numbers, S[i])) then + Exit; + {$ENDIF} + Result := true; + end; +end; + +function StrWithinS(const S, SearchStr : ShortString; + Start : Cardinal; + var Position : Cardinal) : boolean; +var + TmpStr : ShortString; +begin + TmpStr := S; + if (Start > 1) then + System.Delete(TmpStr, 1, Start-1); + Position := pos(SearchStr, TmpStr); + if (Position > 0) then begin + Position := Position + Start - 1; + Result := True; + end else + Result := False; +end; + + +function WordPosS(const S, WordDelims, AWord : ShortString; + N : Cardinal; var Position : Cardinal) : Boolean; + {-returns the Nth instance of a given word within a string} +var + TmpStr : ShortString; + Len, + I, + P1, + P2 : Cardinal; +begin + if (S = '') or (AWord = '') or (Pos(AWord, S) = 0) or (N < 1) then begin + Result := False; + Position := 0; + Exit; + end; + + Result := False; + Position := 0; + + TmpStr := S; + I := 0; + Len := Length(AWord); + P1 := Pos(AWord, TmpStr); + + while (P1 > 0) and (Length(TmpStr) > 0) do begin + P2 := P1 + pred(Len); + if (P1 = 1) then begin + if (Pos(TmpStr[P2+1], WordDelims) > 0) then begin + Inc(I); + end else + System.Delete(TmpStr, 1, P2); + end else if (Pos(TmpStr[P1-1], WordDelims) > 0) and + ((Pos(TmpStr[P2+1], WordDelims) > 0) or + (P2+1 = Length(TmpStr))) then begin + Inc(I); + end else if ((P1 + pred(Len)) = Length(TmpStr)) then begin + if (P1 > 1) and (Pos(TmpStr[P1-1], WordDelims) > 0) then + Inc(I); + end; + + if (I = N) then begin + Result := True; + Position := Position + P1; + Exit; + end; + System.Delete(TmpStr, 1, P2); + Position := Position + P2; + P1 := Pos(AWord, TmpStr); + end; +end; + + +end. diff --git a/components/systools/source/run/sttohtml.pas b/components/systools/source/run/sttohtml.pas new file mode 100644 index 000000000..6ff9415a5 --- /dev/null +++ b/components/systools/source/run/sttohtml.pas @@ -0,0 +1,963 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StToHTML.pas 4.04 *} +{*********************************************************} +{* SysTools: HTML Text Formatter *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +//{$I StDefine.inc} + +unit StToHTML; + +interface + +uses + {$IFNDEF FPC} + Windows, Messages, + {$ENDIF} + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StStrms, StBase; + +type + TStOnProgressEvent = procedure(Sender : TObject; Percent : Word) of object; + + TStStreamToHTML = class(TObject) + protected {private} + { Private declarations } + FCaseSensitive : Boolean; + FCommentMarkers : TStringList; + FEmbeddedHTML : TStringList; + FInFileSize : Cardinal; + FInFixedLineLen : integer; + FInLineTermChar : Char; + FInLineTerminator: TStLineTerminator; + FInputStream : TStream; + FInSize : Cardinal; + FInTextStream : TStAnsiTextStream; + FIsCaseSensitive : Boolean; + FKeywords : TStringList; + FOnProgress : TStOnProgressEvent; + FOutputStream : TStream; + FOutTextStream : TStAnsiTextStream; + FPageFooter : TStringList; + FPageHeader : TStringList; + FStringMarkers : TStringList; + FWordDelims : String; + protected + { Protected declarations } + + {internal methods} + function ParseBuffer : Boolean; + + procedure SetCommentMarkers(Value : TStringList); + procedure SetEmbeddedHTML(Value : TStringList); + procedure SetKeywords(Value : TStringList); + procedure SetPageFooter(Value : TStringList); + procedure SetPageHeader(Value : TStringList); + procedure SetStringMarkers(Value : TStringList); + + public + { Public declarations } + + property CaseSensitive : Boolean + read FCaseSensitive + write FCaseSensitive; + + property CommentMarkers : TStringList + read FCommentMarkers + write SetCommentMarkers; + + property EmbeddedHTML : TStringList + read FEmbeddedHTML + write SetEmbeddedHTML; + + property InFixedLineLength : integer + read FInFixedLineLen + write FInFixedLineLen; + + property InLineTermChar : Char + read FInLineTermChar + write FInLineTermChar; + + property InLineTerminator : TStLineTerminator + read FInLineTerminator + write FInLineTerminator; + + property InputStream : TStream + read FInputStream + write FInputStream; + + property Keywords : TStringList + read FKeywords + write SetKeywords; + + property OnProgress : TStOnProgressEvent + read FOnProgress + write FOnProgress; + + property OutputStream : TStream + read FOutputStream + write FOutputStream; + + property PageFooter : TStringList + read FPageFooter + write SetPageFooter; + + property PageHeader : TStringList + read FPageHeader + write SetPageHeader; + + property StringMarkers : TStringList + read FStringMarkers + write SetStringMarkers; + + property WordDelimiters : String + read FWordDelims + write FWordDelims; + + + constructor Create; + destructor Destroy; override; + + procedure GenerateHTML; + end; + + + TStFileToHTML = class(TStComponent) + protected {private} + { Private declarations } + + FCaseSensitive : Boolean; + FCommentMarkers : TStringList; + FEmbeddedHTML : TStringList; + FInFile : TFileStream; + FInFileName : String; + FInLineLength : integer; + FInLineTermChar : Char; + FInLineTerminator : TStLineTerminator; + FKeywords : TStringList; + FOnProgress : TStOnProgressEvent; + FOutFile : TFileStream; + FOutFileName : String; + FPageFooter : TStringList; + FPageHeader : TStringList; + FStream : TStStreamToHTML; + FStringMarkers : TStringList; + FWordDelims : String; + + protected + + procedure SetCommentMarkers(Value : TStringList); + procedure SetEmbeddedHTML(Value : TStringList); + procedure SetKeywords(Value : TStringList); + procedure SetPageFooter(Value : TStringList); + procedure SetPageHeader(Value : TStringList); + procedure SetStringMarkers(Value : TStringList); + + public + constructor Create(AOwner : TComponent); override; + destructor Destroy; override; + + procedure Execute; + + published + property CaseSensitive : Boolean + read FCaseSensitive + write FCaseSensitive default False; + + property CommentMarkers : TStringList + read FCommentMarkers + write SetCommentMarkers; + + property EmbeddedHTML : TStringList + read FEmbeddedHTML + write SetEmbeddedHTML; + + property InFileName : String + read FInFileName + write FInFileName; + + property InFixedLineLength : integer + read FInLineLength + write FInLineLength default 80; + + property InLineTermChar : Char + read FInLineTermChar + write FInLineTermChar default #10; + + property InLineTerminator : TStLineTerminator + read FInLineTerminator + write FInLineTerminator default ltCRLF; + + property Keywords : TStringList + read FKeywords + write SetKeywords; + + property OnProgress : TStOnProgressEvent + read FOnProgress + write FOnProgress; + + property OutFileName : String + read FOutFileName + write FOutFileName; + + property PageFooter : TStringList + read FPageFooter + write SetPageFooter; + + property PageHeader : TStringList + read FPageHeader + write SetPageHeader; + + property StringMarkers : TStringList + read FStringMarkers + write SetStringMarkers; + + property WordDelimiters : String + read FWordDelims + write FWordDelims; + end; + + +implementation + +uses + StConst, + StDict; + + +(*****************************************************************************) +(* TStStreamToHTML Implementation *) +(*****************************************************************************) + +constructor TStStreamToHTML.Create; +begin + inherited Create; + + FCommentMarkers := TStringList.Create; + FEmbeddedHTML := TStringList.Create; + FKeywords := TStringList.Create; + FPageFooter := TStringList.Create; + FPageHeader := TStringList.Create; + FStringMarkers := TStringList.Create; + + FInputStream := nil; + FOutputStream := nil; + + FInFileSize := 0; + FWordDelims := ',; .()'; + + FInLineTerminator := ltCRLF; {normal Windows text file terminator} + FInLineTermChar := #10; + FInFixedLineLen := 80; + + with FEmbeddedHTML do begin + Add('"="'); + Add('&=&'); + Add('<=<'); + Add('>=>'); + Add('¡=¡'); + Add('¢=¢'); + Add('£=£'); + Add('©=©'); + Add('®=®'); + Add('±=±'); + Add('¼=¼'); + Add('½=½'); + Add('¾=¾'); + Add('÷=÷'); + end; +end; + + +destructor TStStreamToHTML.Destroy; +begin + FCommentMarkers.Free; + FCommentMarkers := nil; + + FEmbeddedHTML.Free; + FEmbeddedHTML := nil; + + FKeywords.Free; + FKeywords := nil; + + FPageFooter.Free; + FPageFooter := nil; + + FPageHeader.Free; + FPageHeader := nil; + + FStringMarkers.Free; + FStringMarkers := nil; + + FInTextStream.Free; + FInTextStream := nil; + + FOutTextStream.Free; + FOutTextStream := nil; + + inherited Destroy; +end; + + +procedure TStStreamToHTML.GenerateHTML; +begin + if not ((Assigned(FInputStream) and (Assigned(FOutputStream)))) then + RaiseStError(EStToHTMLError, stscBadStream) + else + ParseBuffer; +end; + + +procedure DisposeString(Data : Pointer); far; +begin + Dispose(PString(Data)); +end; + + +function TStStreamToHTML.ParseBuffer : Boolean; +var + I, J, + P1, + P2, + BRead, + PC : Longint; + CloseStr, + SStr, + EStr, + S, + VS, + AStr, + TmpStr : String; + P : Pointer; + PS : PString; + CommentDict : TStDictionary; + HTMLDict : TStDictionary; + KeywordsDict : TStDictionary; + StringDict : TStDictionary; + CommentPend : Boolean; + + function ConvertEmbeddedHTML(const Str2 : String) : String; + var + L, + J : Longint; + PH : Pointer; + begin + Result := ''; + {avoid memory reallocations} + SetLength(Result, 1024); + J := 1; + for L := 1 to Length(Str2) do begin + if (not HTMLDict.Exists(Str2[L], PH)) then begin + Result[J] := Str2[L]; + Inc(J); + end else begin + Move(String(PH^)[1], Result[J], Length(String(PH^)) * SizeOf(Char)); + Inc(J, Length(String(PH^))); + end; + end; + Dec(J); + SetLength(Result, J); + end; + + procedure CheckSubString(const Str1 : String); + var + S2 : String; + begin + if (KeywordsDict.Exists(Str1, P)) then begin + VS := String(P^); + S2 := Copy(VS, 1, pos(';', VS)-1) + + ConvertEmbeddedHTML(Str1) + + Copy(VS, pos(';', VS)+1, Length(VS)); + if (P1 >= Length(Str1)) and (P1 <= Length(TmpStr)) then + S2 := S2 + ConvertEmbeddedHTML(TmpStr[P1]); + end else begin + S2 := ConvertEmbeddedHTML(Str1); + if (P1 >= Length(Str1)) and (P1 <= Length(TmpStr)) then + S2 := S2 + ConvertEmbeddedHTML(TmpStr[P1]); + end; + S := S + S2; + end; + +begin + if (Length(FWordDelims) = 0) then + RaiseStError(EStToHTMLError, stscWordDelimiters); + + {create Dictionaries for lookups} + CommentDict := TStDictionary.Create(FCommentMarkers.Count+1); + KeywordsDict := TStDictionary.Create(FKeywords.Count+1); + HTMLDict := TStDictionary.Create(FEmbeddedHTML.Count+1); + StringDict := TStDictionary.Create(FStringMarkers.Count+1); + + CommentDict.DisposeData := DisposeString; + KeywordsDict.DisposeData := DisposeString; + HTMLDict.DisposeData := DisposeString; + StringDict.DisposeData := DisposeString; + + FInTextStream := TStAnsiTextStream.Create(FInputStream); + FInTextStream.LineTermChar := AnsiChar(FInLineTermChar); + FInTextStream.LineTerminator := FInLineTerminator; + FInTextStream.FixedLineLength := FInFixedLineLen; + FInFileSize := FInTextStream.Size; + + FOutTextStream := TStAnsiTextStream.Create(FOutputStream); + FOutTextStream.LineTermChar := #10; + FOutTextStream.LineTerminator := ltCRLF; + FOutTextStream.FixedLineLength := 80; + + FInLineTerminator := ltCRLF; {normal Windows text file terminator} + FInLineTermChar := #10; + FInFixedLineLen := 80; + + try + if (FCaseSensitive) then begin + CommentDict.Hash := AnsiHashStr; + CommentDict.Equal := AnsiCompareStr; + HTMLDict.Hash := AnsiHashStr; + HTMLDict.Equal := AnsiCompareStr; + KeywordsDict.Hash := AnsiHashStr; + KeywordsDict.Equal:= AnsiCompareStr; + StringDict.Hash := AnsiHashStr; + StringDict.Equal := AnsiCompareStr; + end else begin + CommentDict.Hash := AnsiHashText; + CommentDict.Equal := AnsiCompareText; + HTMLDict.Hash := AnsiHashText; + HTMLDict.Equal := AnsiCompareText; + KeywordsDict.Hash := AnsiHashText; + KeywordsDict.Equal:= AnsiCompareText; + StringDict.Hash := AnsiHashText; + StringDict.Equal := AnsiCompareText; + end; + + {Add items from string lists to dictionaries} + for I := 0 to pred(FKeywords.Count) do begin + if (Length(FKeywords[I]) = 0) then + continue; + if (pos('=', FKeywords[I]) > 0) then begin + New(PS); + S := FKeywords.Names[I]; + PS^ := FKeywords.Values[S]; + if (not KeywordsDict.Exists(S, P)) then + KeywordsDict.Add(S, PS) + else + Dispose(PS); + end else + RaiseStError(EStToHTMLError, stscInvalidSLEntry); + end; + + for I := 0 to pred(FStringMarkers.Count) do begin + if (Length(FStringMarkers[I]) = 0) then + continue; + if (pos('=', FStringMarkers[I]) > 0) then begin + New(PS); + S := FStringMarkers.Names[I]; + PS^ := FStringMarkers.Values[S]; + if (not StringDict.Exists(S, P)) then + StringDict.Add(S, PS) + else + Dispose(PS); + end else + RaiseStError(EStToHTMLError, stscInvalidSLEntry); + end; + + for I := 0 to pred(FCommentMarkers.Count) do begin + if (Length(FCommentMarkers[I]) = 0) then + continue; + if (pos('=', FCommentMarkers[I]) > 0) then begin + New(PS); + S := FCommentMarkers.Names[I]; + if (Length(S) = 1) then + PS^ := FCommentMarkers.Values[S] + else begin + PS^ := ':1' + S[2] + ';' + FCommentMarkers.Values[S]; + S := S[1]; + end; + if (not CommentDict.Exists(S, P)) then + CommentDict.Add(S, PS) + else begin + AStr := String(P^); + AStr := AStr + PS^; + String(P^) := AStr; + CommentDict.Update(S, P); + Dispose(PS); + end; + end else + RaiseStError(EStToHTMLError, stscInvalidSLEntry); + end; + + for I := 0 to pred(FEmbeddedHTML.Count) do begin + if (pos('=', FEmbeddedHTML[I]) > 0) then begin + New(PS); + S := FEmbeddedHTML.Names[I]; + PS^ := FEmbeddedHTML.Values[S]; + if (not HTMLDict.Exists(S, P)) then + HTMLDict.Add(S, PS) + else + Dispose(PS); + end else + RaiseStError(EStToHTMLError, stscInvalidSLEntry); + end; + + BRead := 0; + if (FPageHeader.Count > 0) then begin + for I := 0 to pred(FPageHeader.Count) do + FOutTextStream.WriteLine(FPageHeader[I]); + end; + FOutTextStream.WriteLine('<pre>'); + CommentPend := False; + AStr := ''; + SStr := ''; + EStr := ''; + + {make sure buffer is at the start} + FInTextStream.Position := 0; + while not FInTextStream.AtEndOfStream do begin + TmpStr := FInTextStream.ReadLine; + Inc(BRead, Length(TmpStr) + Length(FInTextStream.LineTermChar)); + if (FInFileSize > 0) then begin + PC := Round((BRead / FInFileSize * 100)); + if (Assigned(FOnProgress)) then + FOnProgress(Self, PC); + end; + + if (TmpStr = '') then begin + if (CommentPend) then + FOutTextStream.WriteLine(EStr) + else + FOutTextStream.WriteLine(' '); + continue; + end; + + if (CommentPend) then + S := SStr + else + S := ''; + + P1 := 1; + repeat + if (not CommentPend) and (CommentDict.Exists(TmpStr[P1], P)) then begin + VS := String(P^); + if (Copy(VS, 1 , 2) = ':1') then begin + while (Copy(VS, 1 , 2) = ':1') do begin + System.Delete(VS, 1, 2); + if (TmpStr[P1+1] = VS[1]) then begin + System.Delete(VS, 1, 2); + CloseStr := Copy(VS, 1, pos(';', VS)-1); + System.Delete(VS, 1, pos(';', VS)); + SStr := Copy(VS, 1, pos(';', VS)-1); + System.Delete(VS, 1, pos(';', VS)); + J := pos(':1', VS); + if (J = 0) then + EStr := Copy(VS, pos(';', VS)+1, Length(VS)) + else begin + EStr := Copy(VS, 1, J-1); + System.Delete(VS, 1, J+2); + end; + + if (CloseStr = '') then begin + S := S + SStr; + AStr := Copy(TmpStr, P1, Length(TmpStr)); + CheckSubString(AStr); + S := S + EStr; + CloseStr := ''; + SStr := ''; + EStr := ''; + TmpStr := ''; + continue; + end else begin + I := pos(CloseStr, TmpStr); + if (I = 0) then begin + CommentPend := True; + S := SStr + S; + end else begin + S := S + SStr; + AStr := Copy(TmpStr, P1, I-P1+Length(CloseStr)); + CheckSubstring(AStr); + S := S + EStr; + System.Delete(TmpStr, P1, I-P1+Length(CloseStr)); + end; + end; + end else begin + J := pos(':1', VS); + if (J > 0) then + System.Delete(VS, 1, J-1); + end; + end; + end else begin + {is it really the beginning of a comment?} + CloseStr := Copy(VS, 1, pos(';', VS)-1); + System.Delete(VS, 1, pos(';', VS)); + SStr := Copy(VS, 1, pos(';', VS)-1); + EStr := Copy(VS, pos(';', VS)+1, Length(VS)); + I := pos(CloseStr, TmpStr); + if (I > 0) and (I > P1) then begin + {ending marker found} + CommentPend := False; + S := S + SStr; + AStr := Copy(TmpStr, P1, I-P1+Length(CloseStr)); + CheckSubstring(AStr); + S := S + EStr; + System.Delete(TmpStr, P1, I-P1+Length(CloseStr)); + P1 := 1; + CloseStr := ''; + SStr := ''; + EStr := ''; + if (TmpStr = '') then + continue; + end else begin {1} + CommentPend := True; + S := S + SStr; + if (Length(TmpStr) > 1) then begin + AStr := Copy(TmpStr, P1, Length(TmpStr)); + CheckSubstring(AStr); + end else + S := S + TmpStr; + S := S + EStr; + TmpStr := ''; + continue; + end; + end; + end; + + if (CommentPend) then begin + I := pos(CloseStr, TmpStr); + if (I < 1) then begin + AStr := Copy(TmpStr, P1, Length(TmpStr)); + CheckSubstring(AStr); + S := S + EStr; + TmpStr := ''; + continue; + end else begin {2} + CommentPend := False; + if (Length(TmpStr) > 1) then begin + AStr := Copy(TmpStr, P1, I-P1+Length(CloseStr)); + CheckSubstring(AStr); + end else + S := S + TmpStr; + S := S + EStr; + System.Delete(TmpStr, P1, I-P1+Length(CloseStr)); + CloseStr := ''; + SStr := ''; + EStr := ''; + if (TmpStr = '') then + continue + else + P1 := 1; + end; + end else begin + CloseStr := ''; + SStr := ''; + EStr := ''; + end; + + if (TmpStr = '') then + continue; + + P := nil; + while (P1 <= Length(TmpStr)) and (pos(TmpStr[P1], FWordDelims) = 0) and + (not StringDict.Exists(TmpStr[P1], P)) do + Inc(P1); + if (Assigned(P)) then begin + P2 := P1+1; + VS := String(P^); + CloseStr := Copy(VS, 1, pos(';', VS)-1); + System.Delete(VS, 1, pos(';', VS)); + SStr := Copy(VS, 1, pos(';', VS)-1); + System.Delete(VS, 1, pos(';', VS)); + EStr := Copy(VS, pos(';', VS)+1, Length(VS)); + + while (TmpStr[P2] <> CloseStr) and (P2 <= Length(TmpStr)) do + Inc(P2); + S := S + SStr; + AStr := Copy(TmpStr, P1, P2-P1+1); + CheckSubString(AStr); + S := S + EStr; + + System.Delete(TmpStr, P1, P2); + if (TmpStr = '') then + continue + else + P1 := 1; + P := nil; + end else if (P1 <= Length(TmpStr)) and (pos(TmpStr[P1], FWordDelims) > 0) then begin + if (P1 = 1) then begin + S := S + ConvertEmbeddedHTML(TmpStr[1]); + System.Delete(TmpStr, 1, 1); + P1 := 1; + end else begin + AStr := Copy(TmpStr, 1, P1-1); + if (Length(AStr) > 0) then + CheckSubstring(AStr); + System.Delete(TmpStr, 1, P1); + P1 := 1; + end; + end else begin + AStr := TmpStr; + CheckSubString(AStr); + TmpStr := ''; + end; + until (Length(TmpStr) = 0); + FOutTextStream.WriteLine(S); + end; + if (Assigned(FOnProgress)) then + FOnProgress(Self, 0); + + Result := True; + FOutTextStream.WriteLine('</pre>'); + if (FPageFooter.Count > 0) then begin + for I := 0 to pred(FPageFooter.Count) do + FOutTextStream.WriteLine(FPageFooter[I]); + end; + finally + CommentDict.Free; + HTMLDict.Free; + KeywordsDict.Free; + StringDict.Free; + + FInTextStream.Free; + FInTextStream := nil; + + FOutTextStream.Free; + FOutTextStream := nil; + end; +end; + + +procedure TStStreamToHTML.SetCommentMarkers(Value : TStringList); +begin + FCommentMarkers.Assign(Value); +end; + + +procedure TStStreamToHTML.SetEmbeddedHTML(Value : TStringList); +begin + FEmbeddedHTML.Assign(Value); +end; + + +procedure TStStreamToHTML.SetKeywords(Value : TStringList); +begin + FKeywords.Assign(Value); +end; + + +procedure TStStreamToHTML.SetPageFooter(Value : TStringList); +begin + FPageFooter.Assign(Value); +end; + + +procedure TStStreamToHTML.SetPageHeader(Value : TStringList); +begin + FPageHeader.Assign(Value); +end; + + +procedure TStStreamToHTML.SetStringMarkers(Value : TStringList); +begin + FStringMarkers.Assign(Value); +end; + + + +(*****************************************************************************) +(* TStFileToHTML Implementation *) +(*****************************************************************************) + + +constructor TStFileToHTML.Create(AOwner : TComponent); +begin + inherited Create(AOwner); + + FCommentMarkers := TStringList.Create; + FEmbeddedHTML := TStringList.Create; + FKeywords := TStringList.Create; + FPageFooter := TStringList.Create; + FPageHeader := TStringList.Create; + FStringMarkers := TStringList.Create; + + FWordDelims := ',; .()'; + + FInLineTerminator := ltCRLF; + FInLineTermChar := #10; + FInLineLength := 80; + + with FEmbeddedHTML do begin + Add('"="'); + Add('&=&'); + Add('<=<'); + Add('>=>'); + Add('¡=¡'); + Add('¢=¢'); + Add('£=£'); + Add('©=©'); + Add('®=®'); + Add('±=±'); + Add('¼=¼'); + Add('½=½'); + Add('¾=¾'); + Add('÷=÷'); + end; +end; + + +destructor TStFileToHTML.Destroy; +begin + FCommentMarkers.Free; + FCommentMarkers := nil; + + FEmbeddedHTML.Free; + FEmbeddedHTML := nil; + + FKeywords.Free; + FKeywords := nil; + + FPageFooter.Free; + FPageFooter := nil; + + FPageHeader.Free; + FPageHeader := nil; + + FStringMarkers.Free; + FStringMarkers := nil; + + FInFile.Free; + FInFile := nil; + + FOutFile.Free; + FOutFile := nil; + + FStream.Free; + FStream := nil; + + inherited Destroy; +end; + + +procedure TStFileToHTML.Execute; +begin + FStream := TStStreamToHTML.Create; + try + if (FInFileName = '') then + RaiseStError(EStToHTMLError, stscNoInputFile) + else if (FOutFileName = '') then + RaiseStError(EStToHTMLError, stscNoOutputFile) + else begin + if (Assigned(FInFile)) then + FInFile.Free; + try + FInFile := TFileStream.Create(FInFileName, fmOpenRead or fmShareDenyWrite); + except + RaiseStError(EStToHTMLError, stscInFileError); + Exit; + end; + + if (Assigned(FOutFile)) then + FOutFile.Free; + try + FOutFile := TFileStream.Create(FOutFileName, fmCreate); + except + RaiseStError(EStToHTMLError, stscOutFileError); + Exit; + end; + + try + FStream.InputStream := FInFile; + FStream.OutputStream := FOutFile; + FStream.CaseSensitive := CaseSensitive; + FStream.CommentMarkers := CommentMarkers; + FStream.EmbeddedHTML := EmbeddedHTML; + FStream.InFixedLineLength := InFixedLineLength; + FStream.InLineTermChar := InLineTermChar; + FStream.InLineTerminator := InLineTerminator; + FStream.Keywords := Keywords; + FStream.OnProgress := OnProgress; + FStream.PageFooter := PageFooter; + FStream.PageHeader := PageHeader; + FStream.StringMarkers := StringMarkers; + FStream.WordDelimiters := WordDelimiters; + + FStream.GenerateHTML; + finally + FInFile.Free; + FInFile := nil; + FOutFile.Free; + FOutFile := nil; + end; + end; + finally + FStream.Free; + FStream := nil; + end; +end; + + +procedure TStFileToHTML.SetCommentMarkers(Value : TStringList); +begin + FCommentMarkers.Assign(Value); +end; + + +procedure TStFileToHTML.SetEmbeddedHTML(Value : TStringList); +begin + FEmbeddedHTML.Assign(Value); +end; + + + +procedure TStFileToHTML.SetKeywords(Value : TStringList); +begin + FKeywords.Assign(Value); +end; + + +procedure TStFileToHTML.SetPageFooter(Value : TStringList); +begin + FPageFooter.Assign(Value); +end; + + +procedure TStFileToHTML.SetPageHeader(Value : TStringList); +begin + FPageHeader.Assign(Value); +end; + + +procedure TStFileToHTML.SetStringMarkers(Value : TStringList); +begin + FStringMarkers.Assign(Value); +end; + + +end. diff --git a/components/systools/source/run/stutils.pas b/components/systools/source/run/stutils.pas new file mode 100644 index 000000000..68dc11fc0 --- /dev/null +++ b/components/systools/source/run/stutils.pas @@ -0,0 +1,439 @@ +// Upgraded to Delphi 2009: Sebastian Zierer + +(* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TurboPower SysTools + * + * The Initial Developer of the Original Code is + * TurboPower Software + * + * Portions created by the Initial Developer are Copyright (C) 1996-2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** *) + +{*********************************************************} +{* SysTools: StUtils.pas 4.04 *} +{*********************************************************} +{* SysTools: Assorted utility routines *} +{*********************************************************} + +{$IFDEF FPC} + {$mode DELPHI} +{$ENDIF} + +// {$I StDefine.inc} + +unit StUtils; + +interface + +uses + {$IFNDEF FPC} + Windows, + {$ENDIF} + SysUtils, Classes, + + StConst, StBase, StDate, + StStrL; { long string routines } + +function SignL(L : LongInt) : Integer; + {-return sign of LongInt value} +function SignF(F : Extended) : Integer; + {-return sign of floating point value} + +function MinWord(A, B : Word) : Word; + {-Return the smaller of A and B} +function MidWord(W1, W2, W3 : Word) : Word; + {-return the middle of three Word values} +function MaxWord(A, B : Word) : Word; + {-Return the greater of A and B} + +function MinLong(A, B : LongInt) : LongInt; + {-Return the smaller of A and B} +function MidLong(L1, L2, L3 : LongInt) : LongInt; + {-return the middle of three LongInt values} +function MaxLong(A, B : LongInt) : LongInt; + {-Return the greater of A and B} + +function MinFloat(F1, F2 : Extended) : Extended; + {-return the lesser of two floating point values} +function MidFloat(F1, F2, F3 : Extended) : Extended; + {-return the middle of three floating point values} +function MaxFloat(F1, F2 : Extended) : Extended; + {-return the greater of two floating point values} + +{-Assorted utility routines. } + +function MakeInteger16(H, L : Byte): SmallInt; + {-Construct an integer from two bytes} + +function MakeWord(H, L : Byte) : Word; + {-Construct a word from two bytes} + +function SwapNibble(B : Byte) : Byte; + {-Swap the high and low nibbles of a byte} + +function SwapWord(L : LongInt) : LongInt; + {-Swap the low- and high-order words of a long integer} + +procedure SetFlag(var Flags : Word; FlagMask : Word); + {-Set bit(s) in the parameter Flags. The bits to set are specified in FlagMask} + +procedure ClearFlag(var Flags : Word; FlagMask : Word); + {-Clear bit(s) in the parameter Flags. The bits to clear are specified in Flagmask} + +function FlagIsSet(Flags, FlagMask : Word) : Boolean; + {-Return True if the bit specified by FlagMask is set in Flags} + +procedure SetByteFlag(var Flags : Byte; FlagMask : Byte); + {-Set bit(s) in the parameter Flags. The bits to set are specified in FlagMask} + +procedure ClearByteFlag(var Flags : Byte; FlagMask : Byte); + {-Clear bit(s) in the parameter Flags. The bits to clear are specified in FlagMask} + +function ByteFlagIsSet(Flags, FlagMask : Byte) : Boolean; + {-Return True if the bit specified by FlagMask is set in the Flags parameter} + +procedure SetLongFlag(var Flags : LongInt; FlagMask : LongInt); + {-Set bit(s) in the parameter Flags. The bits to set are specified in FlagMask} + + +procedure ClearLongFlag(var Flags : LongInt; FlagMask : LongInt); + {-Clear bit(s) in the parameter Flags. The bits to clear are specified in FlagMask} + + +function LongFlagIsSet(Flags, FlagMask : LongInt) : Boolean; + {-Return True if the bit specified by FlagMask is set in Flags} + +procedure ExchangeBytes(var I, J : Byte); + {-Exchange the values in two bytes} + +procedure ExchangeWords(var I, J : Word); + {-Exchange the values in two words} + +procedure ExchangeLongInts(var I, J : LongInt); + {-Exchange the values in two long integers} + +procedure ExchangeStructs(var I, J; Size : Cardinal); + {-Exchange the values in two structures} + + +procedure FillWord(var Dest; Count : Cardinal; Filler : Word); + {-Fill memory with a word-sized filler} + +procedure FillStruct(var Dest; Count : Cardinal; var Filler; FillerSize : Cardinal); + {-Fill memory with a variable sized filler} + +function AddWordToPtr(P : Pointer; W : Word) : Pointer; + {-Add a word to a pointer.} + +implementation + +const + ecOutOfMemory = 8; + +function MakeInteger16(H, L : Byte): SmallInt; +begin + Word(Result) := (H shl 8) or L; {!!.02} +end; + +function SwapNibble(B : Byte) : Byte; +begin + Result := (B shr 4) or (B shl 4); +end; + +function SwapWord(L : LongInt) : LongInt; register; +asm + ror eax,16; +end; + +procedure SetFlag(var Flags : Word; FlagMask : Word); +begin + Flags := Flags or FlagMask; +end; + +procedure ClearFlag(var Flags : Word; FlagMask : Word); +begin + Flags := Flags and (not FlagMask); +end; + + +function FlagIsSet(Flags, FlagMask : Word) : Boolean; +begin + Result := (FlagMask AND Flags <> 0); +end; + +procedure SetByteFlag(var Flags : Byte; FlagMask : Byte); +begin + Flags := Flags or FlagMask; +end; + +procedure ClearByteFlag(var Flags : Byte; FlagMask : Byte); +begin + Flags := Flags and (not FlagMask); +end; + +function ByteFlagIsSet(Flags, FlagMask : Byte) : Boolean; +begin + Result := (FlagMask AND Flags <> 0); +end; + +procedure SetLongFlag(var Flags : LongInt; FlagMask : LongInt); +begin + Flags := Flags or FlagMask; +end; + +procedure ClearLongFlag(var Flags : LongInt; FlagMask : LongInt); +begin + Flags := Flags and (not FlagMask); +end; + +function LongFlagIsSet(Flags, FlagMask : LongInt) : Boolean; +begin + Result := FlagMask = (Flags and FlagMask); +end; + +procedure ExchangeBytes(var I, J : Byte); +register; +asm + mov cl, [eax] + mov ch, [edx] + mov [edx], cl + mov [eax], ch +end; + +procedure ExchangeWords(var I, J : Word); +register; +asm + mov cx, [eax] + push ecx + mov cx, [edx] + mov [eax], cx + pop ecx + mov [edx], cx +end; + +procedure ExchangeLongInts(var I, J : LongInt); +register; +asm + mov ecx, [eax] + push ecx + mov ecx, [edx] + mov [eax], ecx + pop ecx + mov [edx], ecx +end; + +procedure ExchangeStructs(var I, J; Size : Cardinal); +register; +asm + push edi + push ebx + push ecx + shr ecx, 2 + jz @@LessThanFour + +@@AgainDWords: + mov ebx, [eax] + mov edi, [edx] + mov [edx], ebx + mov [eax], edi + add eax, 4 + add edx, 4 + dec ecx + jnz @@AgainDWords + +@@LessThanFour: + pop ecx + and ecx, $3 + jz @@Done + mov bl, [eax] + mov bh, [edx] + mov [edx], bl + mov [eax], bh + inc eax + inc edx + dec ecx + jz @@Done + + mov bl, [eax] + mov bh, [edx] + mov [edx], bl + mov [eax], bh + inc eax + inc edx + dec ecx + jz @@Done + + mov bl, [eax] + mov bh, [edx] + mov [edx], bl + mov [eax], bh + +@@Done: + pop ebx + pop edi +end; + +procedure FillWord(var Dest; Count : Cardinal; Filler : Word); +asm + push edi + mov edi,Dest + mov ax,Filler + mov ecx,Count + cld + rep stosw + pop edi +end; + +procedure FillStruct(var Dest; Count : Cardinal; var Filler; + FillerSize : Cardinal); +register; +asm + or edx, edx + jz @@Exit + + push edi + push esi + push ebx + mov edi, eax + mov ebx, ecx + +@@NextStruct: + mov esi, ebx + mov ecx, FillerSize + shr ecx, 1 + rep movsw + adc ecx, ecx + rep movsb + dec edx + jnz @@NextStruct + + pop ebx + pop esi + pop edi + +@@Exit: +end; + +function AddWordToPtr(P : Pointer; W : Word) : Pointer; +begin + Result := Pointer(LongInt(P)+W); +end; + +function MakeWord(H, L : Byte) : Word; +begin + Result := (Word(H) shl 8) or L; +end; + +function MinWord(A, B : Word) : Word; +begin + if A < B then + Result := A + else + Result := B; +end; + +function MaxWord(A, B : Word) : Word; +begin + if A > B then + Result := A + else + Result := B; +end; + +function MinLong(A, B : LongInt) : LongInt; +begin + if A < B then + Result := A + else + Result := B; +end; + +function MaxLong(A, B : LongInt) : LongInt; +begin + if A > B then + Result := A + else + Result := B; +end; + +function SignL(L : LongInt) : Integer; + {-return sign of LongInt value} +begin + if L < 0 then + Result := -1 + else if L = 0 then + Result := 0 + else + Result := 1; +end; + +function SignF(F : Extended) : Integer; + {-return sign of floating point value} +begin + if F < 0 then + Result := -1 + else if F = 0 then + Result := 0 + else + Result := 1; +end; + +function MidWord(W1, W2, W3 : Word) : Word; + {return the middle of three Word values} +begin + Result := StUtils.MinWord(StUtils.MinWord(StUtils.MaxWord(W1, W2), + StUtils.MaxWord(W2, W3)), StUtils.MaxWord(W1, W3)); +end; + +function MidLong(L1, L2, L3 : LongInt) : LongInt; + {return the middle of three LongInt values} +begin + Result := StUtils.MinLong(StUtils.MinLong(StUtils.MaxLong(L1, L2), + StUtils.MaxLong(L2, L3)), StUtils.MaxLong(L1, L3)); +end; + +function MidFloat(F1, F2, F3 : Extended) : Extended; + {return the middle of three floating point values} +begin + Result := MinFloat(MinFloat(MaxFloat(F1, F2), MaxFloat(F2, F3)), MaxFloat(F1, F3)); +end; + +function MinFloat(F1, F2 : Extended) : Extended; + {-return the lesser of two floating point values} +begin + if F1 <= F2 then + Result := F1 + else + Result := F2; +end; + +function MaxFloat(F1, F2 : Extended) : Extended; + {-return the greater of two floating point values} +begin + if F1 > F2 then + Result := F1 + else + Result := F2; +end; + + +end. + + +