UserGuide - Memory access
Some PureBasic instructions, for example those from the Cipher library and many operating system API calls, require a pointer to a memory buffer as an argument rather than the data directly itself. PureBasic provides a number of instructions to manipulate memory buffers to facilitate this.  ;- Compiler Directives
  EnableExplicit
  
  ;- Constants
  ; Window
  Enumeration
    #WindowHex
  EndEnumeration
  
  ; Gadgets
  Enumeration
    #GadgetFiles
    #GadgetOpen
    #GadgetClose
    #GadgetHex
  EndEnumeration
  
  ;- Variables
  Define.l Event, EventWindow, EventGadget, EventType, EventMenu
  Define.l Length
  Define.s File
  Define *Buffer
  
  ;- Declarations
  Declare WindowCreate()
  Declare WindowResize()
  Declare FileClose()
  Declare FileDisplay()
  Declare FileRead()
  
  ;- Implementation
  Procedure WindowCreate()  
    ; Create the window.
    
    Protected.l Col
    Protected.s Label
    
    If OpenWindow(#WindowHex, 50, 50, 500, 400, "Hex View", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
      
      ; Set minimum window size.
      WindowBounds(#WindowHex, 175, 175, #PB_Ignore, #PB_Ignore)
      
      ; Create Explorer List and set to user's home directory.
      ExplorerListGadget(#GadgetFiles, 5, 5, 490, 175, GetHomeDirectory())
      
      ; Buttons.
      ButtonGadget(#GadgetOpen, 5, 185, 80, 25, "Open")
      ButtonGadget(#GadgetClose, 100, 185, 80, 25, "Close")
      
      ; List Icon Gadget.
      ListIconGadget(#GadgetHex, 5, 215, 490, 180, "Offset", 80, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
      
      ; Column Headings.
      For Col = 0 To 7
        Label = RSet(Hex(Col, #PB_Byte), 2, "0")
        AddGadgetColumn(#GadgetHex, Col + 1, Label, 38)
      Next Col
      AddGadgetColumn(#GadgetHex, 9, "Text", 80)
      
    EndIf
    
  EndProcedure
  
  Procedure WindowResize()
    ; Resize gadgets to new window size.
    
    Protected.l X, Y, W, H
    
    ; Explorer List
    W = WindowWidth(#WindowHex) - 10
    H = (WindowHeight(#WindowHex) - 35) / 2
    ResizeGadget(#GadgetFiles, #PB_Ignore, #PB_Ignore, W, H)
    
    ; Buttons
    Y = GadgetHeight(#GadgetFiles) + 10
    ResizeGadget(#GadgetOpen, #PB_Ignore, Y, #PB_Ignore, #PB_Ignore)
    ResizeGadget(#GadgetClose, #PB_Ignore, Y, #PB_Ignore, #PB_Ignore)
    
    ; List Icon View
    Y = (WindowHeight(#WindowHex) / 2) + 23
    W = WindowWidth(#WindowHex) - 10
    H = WindowHeight(#WindowHex) - (Y + 5)
    ResizeGadget(#GadgetHex, #PB_Ignore, Y, W, H)
    
  EndProcedure
  
  Procedure FileClose()
    ; Clear the list view and release the memory buffer.
    
    Shared Length, *Buffer
    
    ClearGadgetItems(#GadgetHex)
    FillMemory(*Buffer, Length)
    FreeMemory(*Buffer)
    
  EndProcedure
  
  Procedure FileDisplay()
    ; Display the file buffer in the list view.
    
    Shared Length, *Buffer
    
    Protected *Byte
    Protected Peek
    Protected.l Rows, Cols, Offset
    Protected.s OffsetString, Row, String
    
    ; Clear current contents.
    ClearGadgetItems(#GadgetHex)
    
    ; Loop through rows.
    For Rows = 0 To Length - 1 Step 8
      
      ; Clear the text value for each row.
      String = ""
      
      ; Convert the offset value to a fixed length string.
      Row = RSet(Hex(Rows, #PB_Long), 6, "0") + Chr(10)
      
      ; Loop through columns.
      For Cols = 0 To 7
        
        ; Calculate the offset for the current column.
        Offset = Rows + Cols
        
        ; Compare the offset with the file length.
        If Offset < Length
          ; The offset is less than the length of the file.
          
          ; Obtain the byte from the buffer.
          *Byte = *Buffer + Offset
          Peek = PeekB(*Byte)
          
          ; Convert the byte to text.
          Row + RSet(Hex(Peek, #PB_Byte), 2, "0") + Chr(10)
          
          ; Add the character to the text version.
          Select Peek
              
            Case 0 To 31, 127
              ; Unprintable characters.
              String + Chr(129)   
              
            Default
              ; Printable characters.
              String + Chr(Peek)
              
          EndSelect
          
        Else
          ; The offset is greater than the length of the file.
          
          ; Add an empty column.
          Row + Chr(10)
          
        EndIf
        
      Next Cols
      
      ; Add the text version at the end of the hex columns.
      Row + String
      
      ; Add the completed row to the list view.
      AddGadgetItem(#GadgetHex, -1, Row)
      
    Next Rows
    
  EndProcedure
  
  Procedure FileRead()
    ; Read the file into the memory buffer.
    
    Shared Length, File, *Buffer
    
    Protected.b ReadByte
    Protected.l FileNumber, ReadLong, Size
    
    ; Stop if file is empty.
    If File = ""
      ProcedureReturn
    EndIf
    
    ; Stop if file size is invalid.
    Size = FileSize(File)
    If Size < 1
      ProcedureReturn 
    EndIf
    
    ; Open the file.
    FileNumber = OpenFile(#PB_Any, File)
    Length = Lof(FileNumber)
    
    If File And Length
      
      ; Allocate a memory buffer to hold the file.
      *Buffer = AllocateMemory(Length)
      
      ; Read the file into the buffer.
      Length = ReadData(FileNumber, *Buffer, Length)
      
    EndIf
    
    ; Close the file.
    CloseFile(FileNumber)
    
  EndProcedure
  
  ;- Main
  WindowCreate()
  
  ;- Event Loop
  Repeat
    
    ; Obtain event parameters.
    Event = WaitWindowEvent()
    EventGadget = EventGadget()
    EventType = EventType()
    EventWindow = EventWindow()
    
    ; Handle events.
    Select Event
        
      Case #PB_Event_Gadget
        If EventGadget = #GadgetFiles
          ; Do nothing.
          
        ElseIf EventGadget = #GadgetOpen
          File = GetGadgetText(#GadgetFiles) + GetGadgetItemText(#GadgetFiles, GetGadgetState(#GadgetFiles))
          If FileSize(File) > 0
            FileRead()  
            FileDisplay()
          EndIf
          
        ElseIf EventGadget = #GadgetClose
          FileClose()
          
        ElseIf EventGadget = #GadgetHex
          ; Do nothing.
          
        EndIf
        
      Case #PB_Event_CloseWindow
        If EventWindow = #WindowHex
          CloseWindow(#WindowHex)
          Break
        EndIf
        
      Case #PB_Event_SizeWindow
        WindowResize()
        
    EndSelect
    
  ForEver
UserGuide Navigation
< Previous: Reading and writing files | Overview | Next: Dynamic numbering using #PB_Any >