properties and functions of THexEditor, a hex edit control for delphi 3/4
(C) 1998-1999 Markus Stephany, mirbir.st@t-online.de

latest changes : V1.15 : jan 03 1999

credits to John Hamm , john@TEMPUS.COM for his nice "cosmetic" modifications and ideas

           Christophe LE CORFEC , CLC@khalif.com for his introduction to the EBCDIC format and
                                  the fine idea about half byte insert/delete

           Philippe Chessa , Philippe_Chessa@compuserve.com for his suggestions about AsText, AsHex
                             and better support for the french keyboard layout

           Daniel Jensen , no_comply@usa.net for octal offset display
                           and the INS-key recognition stuff

  public

    function Seek (const aOffset , aOrigin : Integer ; const FailIfOutOfRange : Boolean ) : Boolean;

             move the current file position ( the cursor ) to :
                  - current position + aOffset, if aOrigin = soFromCurrent
                  - aOffset, if aOrigin = soFromBeginning
                  - file end + aOffset ( aOffset must be less than zero here ), if aOrigin = soFromEnd

             if FailIfOutOfRange is set to True and the new position would be < 0 or >= file size,
             then don't move the cursor and return False,
             if set to False, then goto first or last byte, if the new position is out of range


    function Find ( aBuffer : PChar ; const aCount , aStart , aEnd : Integer ;
             const IgnoreCase , SearchText : Boolean ) : Integer;

             find some data in a part of or the whole file
             aBuffer contains the data to find
             aCount is the size of the searched data
             aStart, aEnd : the range to search in
             IgnoreCase   : if set to true, find also 'such' in 'Suche'
                            ( should be used only in conjunction with SearchText, if set, search is much slower )
             SearchText   : if set to true, the find function will check the Translation property ( s. b. )
                            to find e.g. the german Char '' (html: &uuml;) in a dos/mac etc. text file


             the result is the found position, -1 if data hasen't been found


    procedure DeleteSelection;

              removes the current selection from the file with undo


    function LoadFromStream(Strm: TStream): Boolean;

             returns true if data could have been loaded from  stream Strm


    function LoadFromFile(const Filename: string): Boolean;

             returns true if data could have been loaded from the given file,
             sets the property FileName to the given name and sets the ReadOnly property,
             if the file cannot be written.
             resets undo and Modified


    function SaveToStream(Strm: TStream): Boolean;

             returns true if data could have been loaded from  stream Strm


    function SaveToFile(const Filename: string): Boolean;

             returns true if the could have been saved to the given filename,
             resets Modified and undo


    function Undo : Boolean;

             undo the last performed action if possible, multiple undo up to 100 ( change it by modifiying
             the cMax_Undo constant in HexEditor.pas


    procedure CreateEmptyFile (const TempName : string );

              resets internal structures and makes it possible to modify an unsaved file.
              you should set the TempName to something like 'Unnamed 1'


    function BufferFromFile ( aPos : Integer ; var aCount : Integer ): PChar;

             allocates memory for the result and stores aCount Bytes of the current file from position aPos
             to it


    procedure InsertBuffer ( aBuffer : PChar ; aSize , aPos : Integer );

              insert aBuffer's contents at file's position aPos (amount aSize),
              insert, no overwrite ( for that, see ReplaceSelection )


    procedure AppendBuffer ( aBuffer : PChar ; aSize : Integer);

              appends aBuffer's contents (aSize bytes) behind the last byte of the file


    procedure ReplaceSelection ( aBuffer : PChar ; aSize : Integer );

              replaces the current selection with aBuffer's contents ( aSize and selection count doesn't have
              to match )


    function GetCursorPos : Integer;

             returns the cursor position ( resp. the current file position )


    property SelStart : Integer r/w

             reads/writes the selection start ( sets selection length to 0, sets the cursor position )


    property SelEnd : Integer r/w

             sets/gets the selection end, can be less than SelStart to have a selection from right to the left
             (or bottom to top)


    property SelCount : Integer r

             returns the amount of selected bytes (0..n)


    property CanUndo : Boolean r

             if true, undo is possible


    property InCharField : Boolean r/w

             if true, the cursor caret is set to the (right side) character field, if false, it is in
             the (middle) hex field (read and write)


    property UndoDescription : string r

             returns the description for the currently possible undo ('No Undo' , 'Replace Selection'...)


    property ReadOnly : Boolean r/w

             is the file readonly ( if true, 'Save' should be handled like 'Save as...' )


    property Modified : Boolean r/w

             True, if changes have been made to the current file


    property DataSize : Integer r

             gets the current file's size ( 0 if a new/empty file )


    property Data [ Index : Integer] : Char r/w

             access to the file's contents, byte by byte (slow), also see BufferFromFile for reading more
             than one byte at once, replaceselection for writing some data


    property Filename: string r

             the current file's name, set by LoadFromFile/CreateEmptyFile


  // new for V1.12

    function DeleteNibble ( const aPos : Integer ; const HighNibble : Boolean ) : Boolean;

             removes 4 bits (1 nibble) at the given position, if HighNibble is true,
             bits 16..128 will be deleted else bits 1..8 then shifts the file's contents
             behind these bits bitwise to the left (against pos 0 )
             example :
                      before : 01 23 45 67 89 ab cd ef
                               cursor   ^

                      after  : 01 23 45 78 9a bc de fx
                               cursor   ^


    function InsertNibble ( const aPos : Integer ; const HighNibble : Boolean ) : Boolean;

             inserts 4 bits (1 nibble) at the given position, if HighNibble is true,
             0000 will be inserted at position $80 else at $00 then shifts the file's contents
             behind these bits bitwise to the right (to file end )
             example :
                      before : 01 23 45 67 89 ab cd ef
                               cursor    ^

                      after  : 01 23 45 60 78 9a bc de
                               cursor    ^


    procedure ConvertRange ( const aFrom , aTo : Integer ; const aTransFrom , aTransTo : TTranslationType );

              converts the given file-range from one code type to another, possible values
              for aTransFrom , aTransTo are :
                  ttAnsi , ttDOS8 , ttASCII , ttMAC , ttEBCDIC
              ( for a description, look to Translation property below )


  // new in V1.13


    function ConvertHexToBin ( aFrom , aTo : PChar ; const aCount : Integer ;
                                       const SwapNibbles : Boolean ; var BytesTranslated : Integer ) : PChar;

             translates things like "a0 00 CCDD ef..." to their binary values and
             returns aTO ( aTo may point to the same memory position as aFrom )

             NOTE: this is not an object function !


    function ConvertBinToHex ( aFrom , aTo : PChar ; const aCount : Integer ;
                                       const SwapNibbles : Boolean ) : PChar;

             translates binary data to its hexadecimal representation
             aTo should be different from aFrom ( since aFrom would be overwritten
             before reading its data ). after doing this a 0# will be stored at the end
             of the result

             NOTE: this is not an object function !


    property AsText : string ; r/w

             with this you can replace THexEditor's data by the contents of a string
             you can also read its data into a string (of course there will be some problems
             with the resulting string if the data contains e.g. #0 values )



    property AsHex  : string ; r/w

             to get THexEditor's data in form of a hexadecimal text ( e.g. "56A7C2A0..." )
             (e.g. to avoid #0 char problems )
             or to replace its data by such a string ( even "0000:0102:0304 0506 07 08" is possible)


  // new in V1.14


            fixed the problem with the invalid caret on windows nt
            (changed the bitmap to an object member)
            many thanx to Eric Grange egrange@hotmail.com


    property VariableLineLength : Boolean ; r/w

             if true, each line can display a different amount
             of bytes (overwrites BytesPerLine)


    property LineLength [ Index : Integer ] : Integer ; r/w

             to get/set each line's length


    property LineOffset [ Index : Integer ] : Integer ; r

             to obtain the starting offset for each line
             ( useful when working with variable line lengths )


    procedure SetLineLengths ( aLengths : TList );

              to set all lines' length all in one to
              different values stored in the aLengths parameter


 // new in V1.15


           fixed a problem on creating a THexEditor dynamically
           ( thanks to John Shailes , JohnShailes@email.msn.com )



  published

    property ShowMarkerColumn : Boolean r/w

             if set to true, display an additional column (between offset display and hex field) to
             show marked lines ( mark lines via SHIFT+CTRL+[1..0], jump to them via CTRL+[1..0] )


    property BytesPerColumn : Integer r/w

             how many bytes should be collected to one column in the hexfield, e.g.
             1 : "22 33 44 55..."
             2 : "2233 4455..." and so on, must be at least one


    property OnStateChanged : TNotifyEvent r/w

             gets fired when something has been changed in THexEditor ( caret position, undo, selection and so on)


    property CreateBackup : Boolean r/w

             if set to true, a backup copy will be made of the current file while saving changes
             (see also BackupExtension)


    property BackupExtension : string r/w

             if CreateBackup is set to true, backup copies will have this filename extension
             ( e.g. if "bak", a copy of "ntuser.dat" will be named "ntuser.bak" )


    property OffsetDisplay: TOffsetDisplayStyle r/w

             how the offset ( the line position, left side field) will be displayed
             odHex : 64738 -> '0xFCE2' ( do you remember that number ;-)
             odDec : 64738 -> '64738'
             odNone: the Offset filed won't get displayed


    property BytesPerLine : Integer r/w

             how many bytes should each line contain ( hex and char field )
             ( usually 16,32... but also 137 or 15 are possible (i hope so, not tested) )


    property CaretStyle: TCaretStyle r/w

             how the caret should appear :
             csFull : a full char sized block
             csLeftLine : a left line
             csBottomLine


    property Colors: TColors r/w

             the appearance of THexEditor, a persistent array of colors :

                 Background, the editor's normal background ( set foreground by Font.Color )
                 PositionBackground , PositionText: back/foreground color of line markers
                 ChangedBackground, ChangedText: b/f color of modified bytes
                 CursorFrame: the color of the caret mark in the other field
                 Offset: f color of the offset display field
                 OddColumn: f color of all even columns ("XXXX .... XXXX ....") in the hex field
                 EvenColumn: f color of all odd columns (".... XXXX .... XXXX")


    property FocusFrame: Boolean r/w

             if set to true, the caret mark in the inactive field will be drawn as a "focus" rectangle (dotted lines)
             if false, it will be drawn solid


    property OffsetSeparator: Char r/w

             the char between the offset field and the line marker ( if enabled ) or hex field
             (':' -> "0x0000: 22 33 44..." )
                            ^

  // new for V1.12

    property Translation : TTranslationType r/w

              this can be set to display chars / translate key presses in the char field in various modes,
              currently
                       ttAnsi ( no translation ) ,
                       ttDos8 ( translation to 8 bit dos ascii chars ),
                       ttASCII ( translation to plain 7 bit ascii ) ,
                       ttMac ( chars will be converted to Macintosh(TM) charset ) and
                       ttEBCDIC ( chars will be translated to IBM(TM)'s ebcdic character set, code page 038 )
              are implemented.


    property SwapNibbles: Boolean r/w

             if true the Byte value 160dec will be displayed in hex field as "0A" rather than "A0"


    property Marker [aIndex : Byte] : Integer r/w

             reads/sets the marker position (0..9)


  // new in V1.13


    property MaskWhiteSpaces : Boolean r/w

             if this is true, [#0..#31] chars will be replaced in the char field
             with the char set in the MaskChar property


    property MaskChar       : Char r/w

             the char that will replace white spaces in the char field if MaskWhiteSpaces is true


  // new in V1.14


    property NoSizeChange   : Boolean r/w

             if this is set to true, just overwriting is allowed, no deletion/insertion of data


  // new in V1.15


    the new option odOctal has been added to the TOffsetDisplayStyle type to display line offsets
    in octal (base 8) system.



    property AllowInsertMode: Boolean r/w

             if this is set to true, THexEditor doesn't overwrite but insert values at the current
             cursor position ( this cannot be set if NoSizeChange is True )


    property IsInsertMode   : Boolean r

             if it returns true, the current mode is INS mode (see above )


    property AutoCaretMode  : Boolean r/w

             if true, the caret will be set to a block in overwrite mode and
             to a left line in insert mode automatically





