type int = number ; type float = number ; type size_t = number ; import * as ImGui from "imgui-js" ; export class MemoryEditor { Open : boolean ; ReadOnly : boolean ; Cols : int ; OptShowOptions : boolean ; OptShowDataPreview : boolean ; OptShowHexII : boolean ; OptShowAscii : boolean ; OptGreyOutZeroes : boolean ; OptUpperCaseHex : boolean ; OptMidColsCount : int ; OptAddrDigitsCount : int ; HighlightColor : ImGui . U32 ; public ReadFn : ( ( data : ArrayBuffer , off : size_t ) => size_t ) | null ; public WriteFn : ( ( data : ArrayBuffer , off : size_t , d : number ) => void ) | null ; public HighlightFn : ( ( data : ArrayBuffer , off : size_t ) => boolean ) | null ; ContentsWidthChanged : boolean ; DataPreviewAddr : size_t ; DataEditingAddr : size_t ; DataEditingTakeFocus : boolean ; readonly DataInputBuf : ImGui . StringBuffer = new ImGui . StringBuffer ( 32 ) ; ; readonly AddrInputBuf : ImGui . StringBuffer = new ImGui . StringBuffer ( 32 ) ; ; GotoAddr : size_t ; HighlightMin : size_t ; HighlightMax : size_t ; PreviewEndianess : int ; PreviewDataType : ImGui . DataType ; constructor ( ) { this . Open = true ; this . ReadOnly = false ; this . Cols = 16 ; this . OptShowOptions = true ; this . OptShowDataPreview = false ; this . OptShowHexII = false ; this . OptShowAscii = true ; this . OptGreyOutZeroes = true ; this . OptUpperCaseHex = true ; this . OptMidColsCount = 8 ; this . OptAddrDigitsCount = 0 ; this . HighlightColor = ImGui . COL32 ( 255 , 255 , 255 , 50 ) ; this . ReadFn = null ; this . WriteFn = null ; this . HighlightFn = null ; this . ContentsWidthChanged = false ; this . DataPreviewAddr = this . DataEditingAddr = < size_t > - 1 ; this . DataEditingTakeFocus = false ; this . DataInputBuf . buffer = "" ; this . AddrInputBuf . buffer = "" ; this . GotoAddr = < size_t > - 1 ; this . HighlightMin = this . HighlightMax = < size_t > - 1 ; this . PreviewEndianess = 0 ; this . PreviewDataType = ImGui . DataType . S32 ; } GotoAddrAndHighlight ( addr_min , addr_max ) { this . GotoAddr = addr_min ; this . HighlightMin = addr_min ; this . HighlightMax = addr_max ; } CalcSizes ( s , mem_size , base_display_addr ) { const style = ImGui . GetStyle ( ) ; s . AddrDigitsCount = this . OptAddrDigitsCount ; if ( s . AddrDigitsCount === 0 ) for ( let n = base_display_addr + mem_size - 1 ; n > 0 ; n >>= 4 ) s . AddrDigitsCount ++ ; s . LineHeight = ImGui . GetTextLineHeight ( ) ; s . GlyphWidth = ImGui . CalcTextSize ( "F" ) . x + 1 ; s . HexCellWidth = Math . floor ( s . GlyphWidth * 2.5 ) ; s . SpacingBetweenMidCols = Math . floor ( s . HexCellWidth * 0.25 ) ; s . PosHexStart = ( s . AddrDigitsCount + 2 ) * s . GlyphWidth ; s . PosHexEnd = s . PosHexStart + ( s . HexCellWidth * this . Cols ) ; s . PosAsciiStart = s . PosAsciiEnd = s . PosHexEnd ; if ( this . OptShowAscii ) { s . PosAsciiStart = s . PosHexEnd + s . GlyphWidth * 1 ; if ( this . OptMidColsCount > 0 ) s . PosAsciiStart += ( ( this . Cols + this . OptMidColsCount - 1 ) / this . OptMidColsCount ) * s . SpacingBetweenMidCols ; s . PosAsciiEnd = s . PosAsciiStart + this . Cols * s . GlyphWidth ; } s . WindowWidth = s . PosAsciiEnd + style . ScrollbarSize + style . WindowPadding . x * 2 + s . GlyphWidth ; } public DrawWindow ( title , mem_data , mem_size = mem_data . byteLength , base_display_addr = 0x0000 ) { const s = new MemoryEditor . Sizes ( ) ; this . CalcSizes ( s , mem_size , base_display_addr ) ; ImGui . SetNextWindowSizeConstraints ( new ImGui . Vec2 ( 0.0 , 0.0 ) , new ImGui . Vec2 ( s . WindowWidth , Number . MAX_VALUE ) ) ; this . Open = true ; if ( ImGui . Begin ( title , ( _ = this . Open ) => this . Open = _ , ImGui . WindowFlags . NoScrollbar ) ) { if ( ImGui . IsWindowHovered ( ImGui . HoveredFlags . RootAndChildWindows ) && ImGui . IsMouseReleased ( ImGui . MouseButton . Right ) ) ImGui . OpenPopup ( "context" ) ; this . DrawContents ( mem_data , mem_size , base_display_addr ) ; if ( this . ContentsWidthChanged ) { this . CalcSizes ( s , mem_size , base_display_addr ) ; ImGui . SetWindowSize ( new ImGui . Vec2 ( s . WindowWidth , ImGui . GetWindowSize ( ) . y ) ) ; } } ImGui . End ( ) ; } public DrawContents ( mem_data , mem_size = mem_data . byteLength , base_display_addr = 0x0000 ) { if ( this . Cols < 1 ) this . Cols = 1 ; const s = new MemoryEditor . Sizes ( ) ; this . CalcSizes ( s , mem_size , base_display_addr ) ; const style = ImGui . GetStyle ( ) ; const height_separator = style . ItemSpacing . y ; let footer_height = 0 ; if ( this . OptShowOptions ) footer_height += height_separator + ImGui . GetFrameHeightWithSpacing ( ) * 1 ; if ( this . OptShowDataPreview ) footer_height += height_separator + ImGui . GetFrameHeightWithSpacing ( ) * 1 + ImGui . GetTextLineHeightWithSpacing ( ) * 3 ; ImGui . BeginChild ( "##scrolling" , new ImGui . Vec2 ( 0 , - footer_height ) , false , ImGui . WindowFlags . NoMove | ImGui . WindowFlags . NoNav ) ; const draw_list = ImGui . GetWindowDrawList ( ) ; ImGui . PushStyleVar ( ImGui . StyleVar . FramePadding , new ImGui . Vec2 ( 0 , 0 ) ) ; ImGui . PushStyleVar ( ImGui . StyleVar . ItemSpacing , new ImGui . Vec2 ( 0 , 0 ) ) ; const line_total_count = 0 | ( ( mem_size + this . Cols - 1 ) / this . Cols ) ; const clipper = new ImGui . ListClipper ( ) ; clipper . Begin ( line_total_count , s . LineHeight ) ; clipper . Step ( ) ; const visible_start_addr = clipper . DisplayStart * this . Cols ; const visible_end_addr = clipper . DisplayEnd * this . Cols ; let data_next = false ; if ( this . ReadOnly || this . DataEditingAddr >= mem_size ) this . DataEditingAddr = < size_t > - 1 ; if ( this . DataPreviewAddr >= mem_size ) this . DataPreviewAddr = < size_t > - 1 ; const preview_data_type_size = this . OptShowDataPreview ? this . DataTypeGetSize ( this . PreviewDataType ) : 0 ; let data_editing_addr_backup = this . DataEditingAddr ; let data_editing_addr_next = < size_t > - 1 ; if ( this . DataEditingAddr !== < size_t > - 1 ) { if ( ImGui . IsKeyPressed ( ImGui . GetKeyIndex ( ImGui . Key . UpArrow ) ) && this . DataEditingAddr >= < size_t > this . Cols ) { data_editing_addr_next = this . DataEditingAddr - this . Cols ; this . DataEditingTakeFocus = true ; } else if ( ImGui . IsKeyPressed ( ImGui . GetKeyIndex ( ImGui . Key . DownArrow ) ) && this . DataEditingAddr < mem_size - this . Cols ) { data_editing_addr_next = this . DataEditingAddr + this . Cols ; this . DataEditingTakeFocus = true ; } else if ( ImGui . IsKeyPressed ( ImGui . GetKeyIndex ( ImGui . Key . LeftArrow ) ) && this . DataEditingAddr > 0 ) { data_editing_addr_next = this . DataEditingAddr - 1 ; this . DataEditingTakeFocus = true ; } else if ( ImGui . IsKeyPressed ( ImGui . GetKeyIndex ( ImGui . Key . RightArrow ) ) && this . DataEditingAddr < mem_size - 1 ) { data_editing_addr_next = this . DataEditingAddr + 1 ; this . DataEditingTakeFocus = true ; } } if ( data_editing_addr_next !== < size_t > - 1 && ( data_editing_addr_next / this . Cols ) !== ( data_editing_addr_backup / this . Cols ) ) { const scroll_offset = ( ( data_editing_addr_next / this . Cols ) - ( data_editing_addr_backup / this . Cols ) ) ; const scroll_desired = ( scroll_offset < 0 && data_editing_addr_next < visible_start_addr + this . Cols * 2 ) || ( scroll_offset > 0 && data_editing_addr_next > visible_end_addr - this . Cols * 2 ) ; if ( scroll_desired ) ImGui . SetScrollY ( ImGui . GetScrollY ( ) + scroll_offset * s . LineHeight ) ; } const window_pos = ImGui . GetWindowPos ( ) ; if ( this . OptShowAscii ) draw_list . AddLine ( new ImGui . Vec2 ( window_pos . x + s . PosAsciiStart - s . GlyphWidth , window_pos . y ) , new ImGui . Vec2 ( window_pos . x + s . PosAsciiStart - s . GlyphWidth , window_pos . y + 9999 ) , ImGui . GetColorU32 ( ImGui . Col . Border ) ) ; const color_text = ImGui . GetColorU32 ( ImGui . Col . Text ) ; const color_disabled = this . OptGreyOutZeroes ? ImGui . GetColorU32 ( ImGui . Col . TextDisabled ) : color_text ; const format_address = ( n , a ) : string => { let s = a . toString ( 16 ) . padStart ( n , "0" ) ; if ( this . OptUpperCaseHex ) { s = s . toUpperCase ( ) ; } return s ; } ; const format_data = ( n , a ) : string => { let s = a . toString ( 16 ) . padStart ( n , "0" ) ; if ( this . OptUpperCaseHex ) { s = s . toUpperCase ( ) ; } return s ; } ; const format_byte = ( b ) : string => { let s = b . toString ( 16 ) . padStart ( 2 , "0" ) ; if ( this . OptUpperCaseHex ) { s = s . toUpperCase ( ) ; } return s ; } ; const format_byte_space = ( b ) : string => { return `${ format_byte ( b ) } ` ; } ; for ( let line_i = clipper . DisplayStart ; line_i < clipper . DisplayEnd ; line_i ++ ) { let addr = < size_t > ( line_i * this . Cols ) ; ImGui . Text ( format_address ( s . AddrDigitsCount , base_display_addr + addr ) ) ; for ( let n = 0 ; n < this . Cols && addr < mem_size ; n ++ , addr ++ ) { let byte_pos_x = s . PosHexStart + s . HexCellWidth * n ; if ( this . OptMidColsCount > 0 ) byte_pos_x += ( n / this . OptMidColsCount ) * s . SpacingBetweenMidCols ; ImGui . SameLine ( byte_pos_x ) ; const is_highlight_from_user_range = ( addr >= this . HighlightMin && addr < this . HighlightMax ) ; const is_highlight_from_user_func = ( this . HighlightFn !== null && this . HighlightFn ( mem_data , addr ) ) ; const is_highlight_from_preview = ( addr >= this . DataPreviewAddr && addr < this . DataPreviewAddr + preview_data_type_size ) ; if ( is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview ) { const pos = ImGui . GetCursorScreenPos ( ) ; let highlight_width = s . GlyphWidth * 2 ; const is_next_byte_highlighted = ( addr + 1 < mem_size ) && ( ( this . HighlightMax !== < size_t > - 1 && addr + 1 < this . HighlightMax ) || ( this . HighlightFn !== null && this . HighlightFn ( mem_data , addr + 1 ) ) ) ; if ( is_next_byte_highlighted || ( n + 1 === this . Cols ) ) { highlight_width = s . HexCellWidth ; if ( this . OptMidColsCount > 0 && n > 0 && ( n + 1 ) < this . Cols && ( ( n + 1 ) % this . OptMidColsCount ) === 0 ) highlight_width += s . SpacingBetweenMidCols ; } draw_list . AddRectFilled ( pos , new ImGui . Vec2 ( pos . x + highlight_width , pos . y + s . LineHeight ) , this . HighlightColor ) ; } if ( this . DataEditingAddr === addr ) { let data_write = false ; ImGui . PushID ( addr ) ; if ( this . DataEditingTakeFocus ) { ImGui . SetKeyboardFocusHere ( ) ; ImGui . CaptureKeyboardFromApp ( true ) ; this . AddrInputBuf . buffer = format_data ( s . AddrDigitsCount , base_display_addr + addr ) ; this . DataInputBuf . buffer = format_byte ( this . ReadFn ? this . ReadFn ( mem_data , addr ) : new Uint8Array ( mem_data ) [ addr ] ) ; } ImGui . PushItemWidth ( s . GlyphWidth * 2 ) ; class UserData { static Callback ( data ) { const user_data = data . UserData ; ImGui . ASSERT ( user_data !== null ) ; if ( ! data . HasSelection ( ) ) user_data . CursorPos = data . CursorPos ; if ( data . SelectionStart === 0 && data . SelectionEnd === data . BufTextLen ) { data . DeleteChars ( 0 , data . BufTextLen ) ; data . InsertChars ( 0 , user_data . CurrentBufOverwrite . buffer ) ; data . SelectionStart = 0 ; data . SelectionEnd = 2 ; data . CursorPos = 0 ; } return 0 ; } readonly CurrentBufOverwrite : ImGui . StringBuffer = new ImGui . StringBuffer ( 3 ) ; CursorPos : number = 0 ; } const user_data = new UserData ( ) ; user_data . CursorPos = - 1 ; user_data . CurrentBufOverwrite . buffer = format_byte ( this . ReadFn ? this . ReadFn ( mem_data , addr ) : new Uint8Array ( mem_data ) [ addr ] ) ; const flags = ImGui . InputTextFlags . CharsHexadecimal | ImGui . InputTextFlags . EnterReturnsTrue | ImGui . InputTextFlags . AutoSelectAll | ImGui . InputTextFlags . NoHorizontalScroll | ImGui . InputTextFlags . AlwaysOverwrite | ImGui . InputTextFlags . CallbackAlways ; if ( ImGui . InputText ( "##data" , this . DataInputBuf , 32 , flags , UserData . Callback , user_data ) ) data_write = data_next = true ; else if ( ! this . DataEditingTakeFocus && ! ImGui . IsItemActive ( ) ) this . DataEditingAddr = data_editing_addr_next = < size_t > - 1 ; this . DataEditingTakeFocus = false ; ImGui . PopItemWidth ( ) ; if ( user_data . CursorPos >= 2 ) data_write = data_next = true ; if ( data_editing_addr_next !== < size_t > - 1 ) data_write = data_next = false ; let data_input_value = 0 ; if ( data_write && Number . isInteger ( data_input_value = parseInt ( this . DataInputBuf . buffer , 16 ) ) ) { if ( this . WriteFn ) this . WriteFn ( mem_data , addr , data_input_value ) ; else new Uint8Array ( mem_data ) [ addr ] = data_input_value ; } ImGui . PopID ( ) ; } else { const b = this . ReadFn ? this . ReadFn ( mem_data , addr ) : new Uint8Array ( mem_data ) [ addr ] ; if ( this . OptShowHexII ) { if ( ( b >= 32 && b < 128 ) ) ImGui . Text ( `.${ String . fromCharCode ( b ) } ` ) ; else if ( b === 0xFF && this . OptGreyOutZeroes ) ImGui . TextDisabled ( "## " ) ; else if ( b === 0x00 ) ImGui . Text ( "   " ) ; else ImGui . Text ( format_byte_space ( b ) ) ; } else { if ( b === 0 && this . OptGreyOutZeroes ) ImGui . TextDisabled ( "00 " ) ; else ImGui . Text ( format_byte_space ( b ) ) ; } if ( ! this . ReadOnly && ImGui . IsItemHovered ( ) && ImGui . IsMouseClicked ( 0 ) ) { this . DataEditingTakeFocus = true ; data_editing_addr_next = addr ; } } } if ( this . OptShowAscii ) { ImGui . SameLine ( s . PosAsciiStart ) ; const pos = ImGui . GetCursorScreenPos ( ) ; addr = line_i * this . Cols ; ImGui . PushID ( line_i ) ; if ( ImGui . InvisibleButton ( "ascii" , new ImGui . Vec2 ( s . PosAsciiEnd - s . PosAsciiStart , s . LineHeight ) ) ) { this . DataEditingAddr = this . DataPreviewAddr = addr + < size_t > ( ( ImGui . GetIO ( ) . MousePos . x - pos . x ) / s . GlyphWidth ) ; this . DataEditingTakeFocus = true ; } ImGui . PopID ( ) ; for ( let n = 0 ; n < this . Cols && addr < mem_size ; n ++ , addr ++ ) { if ( addr === this . DataEditingAddr ) { draw_list . AddRectFilled ( pos , new ImGui . Vec2 ( pos . x + s . GlyphWidth , pos . y + s . LineHeight ) , ImGui . GetColorU32 ( ImGui . Col . FrameBg ) ) ; draw_list . AddRectFilled ( pos , new ImGui . Vec2 ( pos . x + s . GlyphWidth , pos . y + s . LineHeight ) , ImGui . GetColorU32 ( ImGui . Col . TextSelectedBg ) ) ; } const c = this . ReadFn ? this . ReadFn ( mem_data , addr ) : new Uint8Array ( mem_data ) [ addr ] ; const display_c = ( c < 32 || c >= 128 ) ? "." : String . fromCharCode ( c ) ; draw_list . AddText ( pos , ( display_c === "." ) ? color_disabled : color_text , display_c ) ; pos . x += s . GlyphWidth ; } } } ImGui . ASSERT ( clipper . Step ( ) === false ) ; clipper . End ( ) ; ImGui . PopStyleVar ( 2 ) ; ImGui . EndChild ( ) ; if ( data_next && this . DataEditingAddr < mem_size ) { this . DataEditingAddr = this . DataPreviewAddr = this . DataEditingAddr + 1 ; this . DataEditingTakeFocus = true ; } else if ( data_editing_addr_next !== < size_t > - 1 ) { this . DataEditingAddr = this . DataPreviewAddr = data_editing_addr_next ; } const lock_show_data_preview = this . OptShowDataPreview ; if ( this . OptShowOptions ) { ImGui . Separator ( ) ; this . DrawOptionsLine ( s , mem_data , mem_size , base_display_addr ) ; } if ( lock_show_data_preview ) { ImGui . Separator ( ) ; this . DrawPreviewLine ( s , mem_data , mem_size , base_display_addr ) ; } ImGui . SetCursorPosX ( s . WindowWidth ) ; } DrawOptionsLine ( s , mem_data , mem_size , base_display_addr ) { const style = ImGui . GetStyle ( ) ; const format_range = ( n_min , a_min , n_max , a_max ) : string => { let s_min = a_min . toString ( 16 ) . padStart ( n_min , "0" ) ; let s_max = a_max . toString ( 16 ) . padStart ( n_max , "0" ) ; if ( this . OptUpperCaseHex ) { s_min = s_min . toUpperCase ( ) ; s_max = s_max . toUpperCase ( ) ; } return `Range ${ s_min }..${ s_max }` ; } ; if ( ImGui . Button ( "Options" ) ) ImGui . OpenPopup ( "context" ) ; if ( ImGui . BeginPopup ( "context" ) ) { ImGui . PushItemWidth ( 56 ) ; if ( ImGui . DragInt ( "##cols" , ( _ = this . Cols ) => this . Cols = _ , 0.2 , 4 , 32 , "%d cols" ) ) { this . ContentsWidthChanged = true ; if ( this . Cols < 1 ) this . Cols = 1 ; } ImGui . PopItemWidth ( ) ; ImGui . Checkbox ( "Show Data Preview" , ( _ = this . OptShowDataPreview ) => this . OptShowDataPreview = _ ) ; ImGui . Checkbox ( "Show HexII" , ( _ = this . OptShowHexII ) => this . OptShowHexII = _ ) ; if ( ImGui . Checkbox ( "Show Ascii" , ( _ = this . OptShowAscii ) => this . OptShowAscii = _ ) ) { this . ContentsWidthChanged = true ; } ImGui . Checkbox ( "Grey out zeroes" , ( _ = this . OptGreyOutZeroes ) => this . OptGreyOutZeroes = _ ) ; ImGui . Checkbox ( "Uppercase Hex" , ( _ = this . OptUpperCaseHex ) => this . OptUpperCaseHex = _ ) ; ImGui . EndPopup ( ) ; } ImGui . SameLine ( ) ; ImGui . Text ( format_range ( s . AddrDigitsCount , base_display_addr , s . AddrDigitsCount , base_display_addr + mem_size - 1 ) ) ; ImGui . SameLine ( ) ; ImGui . PushItemWidth ( ( s . AddrDigitsCount + 1 ) * s . GlyphWidth + style . FramePadding . x * 2.0 ) ; if ( ImGui . InputText ( "##addr" , this . AddrInputBuf , 32 , ImGui . InputTextFlags . CharsHexadecimal | ImGui . InputTextFlags . EnterReturnsTrue ) ) { let goto_addr ; if ( Number . isInteger ( goto_addr = parseInt ( this . AddrInputBuf . buffer , 16 ) ) ) { this . GotoAddr = goto_addr - base_display_addr ; this . HighlightMin = this . HighlightMax = < size_t > - 1 ; } } ImGui . PopItemWidth ( ) ; if ( this . GotoAddr !== < size_t > - 1 ) { if ( this . GotoAddr < mem_size ) { ImGui . BeginChild ( "##scrolling" ) ; ImGui . SetScrollFromPosY ( ImGui . GetCursorStartPos ( ) . y + ( this . GotoAddr / this . Cols ) * ImGui . GetTextLineHeight ( ) ) ; ImGui . EndChild ( ) ; this . DataEditingAddr = this . DataPreviewAddr = this . GotoAddr ; this . DataEditingTakeFocus = true ; } this . GotoAddr = < size_t > - 1 ; } } DrawPreviewLine ( s , mem_data , mem_size , base_display_addr ) { const style = ImGui . GetStyle ( ) ; ImGui . AlignTextToFramePadding ( ) ; ImGui . Text ( "Preview as:" ) ; ImGui . SameLine ( ) ; ImGui . PushItemWidth ( ( s . GlyphWidth * 10.0 ) + style . FramePadding . x * 2.0 + style . ItemInnerSpacing . x ) ; if ( ImGui . BeginCombo ( "##combo_type" , this . DataTypeGetDesc ( this . PreviewDataType ) , ImGui . ComboFlags . HeightLargest ) ) { for ( let n = 0 ; n < ImGui . DataType . COUNT ; n ++ ) if ( ImGui . Selectable ( this . DataTypeGetDesc ( < ImGui . DataType > n ) , this . PreviewDataType === n ) ) this . PreviewDataType = < ImGui . DataType > n ; ImGui . EndCombo ( ) ; } ImGui . PopItemWidth ( ) ; ImGui . SameLine ( ) ; ImGui . PushItemWidth ( ( s . GlyphWidth * 6.0 ) + style . FramePadding . x * 2.0 + style . ItemInnerSpacing . x ) ; ImGui . Combo ( "##combo_endianess" , ( _ = this . PreviewEndianess ) => this . PreviewEndianess = _ , "LE\0BE\0\0" ) ; ImGui . PopItemWidth ( ) ; const buf = new ImGui . StringBuffer ( 128 ) ; const x = s . GlyphWidth * 6.0 ; const has_value = this . DataPreviewAddr !== < size_t > - 1 ; if ( has_value ) this . DrawPreviewData ( this . DataPreviewAddr , mem_data , mem_size , this . PreviewDataType , MemoryEditor . DataFormat . Dec , buf , < size_t > ImGui . ARRAYSIZE ( buf ) ) ; ImGui . Text ( "Dec" ) ; ImGui . SameLine ( x ) ; ImGui . TextUnformatted ( has_value ? buf . buffer : "N/A" ) ; if ( has_value ) this . DrawPreviewData ( this . DataPreviewAddr , mem_data , mem_size , this . PreviewDataType , MemoryEditor . DataFormat . Hex , buf , < size_t > ImGui . ARRAYSIZE ( buf ) ) ; ImGui . Text ( "Hex" ) ; ImGui . SameLine ( x ) ; ImGui . TextUnformatted ( has_value ? buf . buffer : "N/A" ) ; if ( has_value ) this . DrawPreviewData ( this . DataPreviewAddr , mem_data , mem_size , this . PreviewDataType , MemoryEditor . DataFormat . Bin , buf , < size_t > ImGui . ARRAYSIZE ( buf ) ) ; ImGui . Text ( "Bin" ) ; ImGui . SameLine ( x ) ; ImGui . TextUnformatted ( has_value ? buf . buffer : "N/A" ) ; } DataTypeGetDesc ( data_type ) { const descs = [ "Int8" , "Uint8" , "Int16" , "Uint16" , "Int32" , "Uint32" , "Int64" , "Uint64" , "Float" , "Double" ] ; ImGui . ASSERT ( data_type >= 0 && data_type < ImGui . DataType . COUNT ) ; return descs [ data_type ] ; } DataTypeGetSize ( data_type ) { const sizes = [ 1 , 1 , 2 , 2 , 4 , 4 , 8 , 8 , 4 , 8 ] ; ImGui . ASSERT ( data_type >= 0 && data_type < ImGui . DataType . COUNT ) ; return sizes [ data_type ] ; } DataFormatGetDesc ( data_format ) { const descs = [ "Bin" , "Dec" , "Hex" ] ; ImGui . ASSERT ( data_format >= 0 && data_format < MemoryEditor . DataFormat . COUNT ) ; return descs [ data_format ] ; } IsBigEndian ( ) { const x = new Uint16Array ( [ 1 ] ) ; const c = new Int8Array ( x . buffer ) ; return c [ 0 ] !== 0 ; } DrawPreviewData ( addr , mem_data , mem_size , data_type , data_format , out_buf , out_buf_size ) { const buf = new Uint8Array ( 8 ) ; const elem_size = this . DataTypeGetSize ( data_type ) ; const size = addr + elem_size > mem_size ? mem_size - addr : elem_size ; if ( this . ReadFn ) for ( let i = 0 , n = size ; i < n ; ++ i ) buf [ i ] = this . ReadFn ( mem_data , addr + i ) ; else buf . set ( new Uint8Array ( mem_data , addr , size ) ) ; if ( this . PreviewEndianess ) { new Uint8Array ( buf . buffer , 0 , size ) . reverse ( ) ; } if ( data_format === MemoryEditor . DataFormat . Bin ) { out_buf . buffer = "" ; for ( let i = 0 ; i < size ; ++ i ) { out_buf . buffer += buf [ i ] . toString ( 2 ) . padStart ( 8 , "0" ) + " " ; } return ; } out_buf . buffer = "" ; switch ( data_type ) { case ImGui . DataType . S8 : { const int8 = new Int8Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = int8 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ int8 [ 0 ] . toString ( 16 ) . padStart ( 2 , "0" ) }` ; return ; } break ; } case ImGui . DataType . U8 : { const uint8 = new Uint8Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = uint8 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ uint8 [ 0 ] . toString ( 16 ) . padStart ( 2 , "0" ) }` ; return ; } break ; } case ImGui . DataType . S16 : { const int16 = new Int16Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = int16 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ int16 [ 0 ] . toString ( 16 ) . padStart ( 4 , "0" ) }` ; return ; } break ; } case ImGui . DataType . U16 : { const uint16 = new Uint16Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = uint16 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ uint16 [ 0 ] . toString ( 16 ) . padStart ( 4 , "0" ) }` ; return ; } break ; } case ImGui . DataType . S32 : { const int32 = new Int32Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = int32 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ int32 [ 0 ] . toString ( 16 ) . padStart ( 8 , "0" ) }` ; return ; } break ; } case ImGui . DataType . U32 : { const uint32 = new Uint32Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = uint32 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ uint32 [ 0 ] . toString ( 16 ) . padStart ( 8 , "0" ) }` ; return ; } break ; } case ImGui . DataType . S64 : { const int64 = new BigInt64Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = int64 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ int64 [ 0 ] . toString ( 16 ) . padStart ( 16 , "0" ) }` ; return ; } break ; } case ImGui . DataType . U64 : { const uint64 = new BigUint64Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = uint64 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ uint64 [ 0 ] . toString ( 16 ) . padStart ( 16 , "0" ) }` ; return ; } break ; } case ImGui . DataType . Float : { const float32 = new Float32Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = float32 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ float32 [ 0 ] . toString ( 16 ) }` ; return ; } break ; } case ImGui . DataType . Double : { const float64 = new Float64Array ( buf . buffer ) ; if ( data_format === MemoryEditor . DataFormat . Dec ) { out_buf . buffer = float64 [ 0 ] . toString ( ) ; return ; } if ( data_format === MemoryEditor . DataFormat . Hex ) { out_buf . buffer = `0x${ float64 [ 0 ] . toString ( 16 ) }` ; return ; } break ; } case ImGui . DataType . COUNT : break ; } } } export namespace MemoryEditor { export enum DataFormat { Bin = 0 , Dec = 1 , Hex = 2 , COUNT } export class Sizes { AddrDigitsCount : int = 0 ; LineHeight : float = 0.0 ; GlyphWidth : float = 0.0 ; HexCellWidth : float = 0.0 ; SpacingBetweenMidCols : float = 0.0 ; PosHexStart : float = 0.0 ; PosHexEnd : float = 0.0 ; PosAsciiStart : float = 0.0 ; PosAsciiEnd : float = 0.0 ; WindowWidth : float = 0.0 ; } }