logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

C++Builder 5: Jak wyświetlić dane binarne z pliku *.bin w formacie HEX?

pietrek_pl 13 Gru 2002 14:00 4085 11
REKLAMA
  • #1 64677
    pietrek_pl
    Poziom 19  
    Posty: 402
    Pomógł: 23
    Ocena: 46
    Mam problem. Może ktoś pisze pod C++Builder 5. Nie wiem jak sobie poradzić z wyprowadzeniem danych binarnych np. z pliku *.bin na ekran w postaci hex, a nie ASCII.
  • REKLAMA
  • #2 253892
    Pyku
    Poziom 13  
    Posty: 32
    żeby z ASCII zrobić hex - mam na myśli wyświetlenie trzeba każdy odczytany bajt osobno zamienić na liczbę hex (dwa znaki) i tak

    char znak1, znak2, bajt;

    znak1=((bajt/16)<10)?(bajt/16)+48:(bajt/16)+55;
    znak2=((bajt%16)<10)?(bajt%16)+48:(bajt%16)+55;

    o ile dobrze pamiętam % to reszta z dzielenia
    jeśli czegoś nie pomyliłem każdy bajt po odczytaniu z pliku i konwersji wg w/w wzorów można pokazać na ekranie:

    "Bajt %d w hex = %c%c",bajt,znak1,znak2
    tak by to było w C, wystarczy wstawić do Buildera
  • #3 258778
    ElGregor
    Poziom 23  
    Posty: 654
    Pomógł: 2
    Ocena: 56
    :arrow: Pyku
    W Builderze nie trzeba tyle kombinować, jest funkcja IntToHex, która zamienia liczbę całkowitą int na hexadecymalną w postaci tekstu typu AnsiString. Funkcja ma dwa parametry, pierwszy to liczba do konwersji, drugi to liczba cyfr hexadecymalnych jakie zostaną wygenerowane.

    Spróbuj zrobić coś takiego:
    Użyj komponentu np. Label i wpisz w jakiejś funkcji:
    Label1->Caption = IntToHex(52,4);
    Po wykonaniu tej instrukcji w polu Label1 powinna się pojawić liczna 0034 (hexadecymalny odpowiednik liczby 52), liczba jest czterocyfrowa.

    Poza tym pietrek_pl już chyba sobie poradził z problemem konwersji od grudnia 2002roku :D
  • #4 258791
    Pyku
    Poziom 13  
    Posty: 32
    Nie wiedziałem bo nie szukałem bo nie potrzebowałem. Dzięki ElGregor! Zrówko. :wink:
  • REKLAMA
  • #5 260902
    pietrek_pl
    Poziom 19  
    Posty: 402
    Pomógł: 23
    Ocena: 46
    Cześć.
    Jeszcze sobie nie poradził tylko nikt nie odpisywał to co się miałem naprzykrzać.
  • #6 260982
    ElGregor
    Poziom 23  
    Posty: 654
    Pomógł: 2
    Ocena: 56
    :arrow: pietrek_pl
    A widzisz, trzeba było się naprzykrzać to by ktoś szybciej na ten post trafił :D , zresztą gdyby nie Pyku to bym go nie zauważył, a tak pojawił się w nowych postach.
  • #7 261512
    pietrek_pl
    Poziom 19  
    Posty: 402
    Pomógł: 23
    Ocena: 46
    Cześć.
    Zrobiłem to w trochę inny sposób ale to nie jest jeszcze to oco mi chodzi:
    -------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    AnsiString EditText = Edit1->Text;
    Label1->Caption = "";
    Label2->Caption = "";
    for (int i=1;i<=EditText.Length();i++)
    {
    Label1->Caption = Label1->Caption + IntToHex(EditText[i],2) + " ";
    Label2->Caption = Label2->Caption + EditText[i] + "";
    }
    }
    -------
    Chcę odczytać plik z dysku np. mapę pamięci wielkości 512 bajtów i wyświetlić ją na ekranie w ten sposób:

    0000: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF : YYYYYYYYYYYYYYYY
    0010: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF : YYYYYYYYYYYYYYYY
    0020: FF FF FF FF FF FF FF FF - FF FF FF FF FF FF FF FF : YYYYYYYYYYYYYYYY
    itd. gdzie FF to dane w postaci HEX odczytane z dysku, a Y to dane w postaci Ansi.
    Był bym wdzięczny za pomoc.
  • REKLAMA
  • #8 261643
    ElGregor
    Poziom 23  
    Posty: 654
    Pomógł: 2
    Ocena: 56
    Jeśli chcesz to wyświetlić w postaci komponentu Label to prosze oto gotowa procedura:
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      unsigned char InputData[512];
      unsigned char b;
      int i,j;
    
      Label1->Caption = "";
      for (i=0; i<512/16; i++)
      {
        Label1->Caption = Label1->Caption + IntToHex(i*16,4) + " ";
        for (j=0; j<16; j++)
        {
          Label1->Caption = Label1->Caption + IntToHex(InputData[i*16+j],2) + " ";
          if (j==7)
            Label1->Caption = Label1->Caption + "- ";
        }
        for (j=0; j<16; j++)
        {
          b = InputData[i*16+j];
          if (b < ' ' | b > 'z') b = '.';   //test czy bajt jest poprawnym ASCII
          Label1->Caption = Label1->Caption + char(b);
        }
       Label1->Caption = Label1->Caption + "\n";
      }
    }
    Dane załaduj do tablicy "InputData" i nie zapomnij zmienić fontu dla Label1 (np. "Courier New"), bo przy proporcjonalnym różna szerokość znaków "rozstrzeli" ci kolumnę i będzie brzydko wyglądać.
  • #9 264569
    pietrek_pl
    Poziom 19  
    Posty: 402
    Pomógł: 23
    Ocena: 46
    Cześć.
    Wykombinowałem coś takiego:

    void __fastcall TMainForm::CreateMDIChild(String Name)
    {
    TMDIChild *Child;

    //--- create a new MDI child window ----
    Child = new TMDIChild(Application);
    Child->Caption = Name;
    if (FileExists (Name))
    Child->Memo1->Lines->LoadFromFile(Name);

    unsigned char InputData[512];
    unsigned char b;
    int i,j;

    Child->Memo1->Lines->Text = "";


    for (i=0; i<512/16; i++)
    {
    Child->Memo1->Lines->Text = Child->Memo1->Lines->Text + " " + IntToHex(i*16,5) + ") ";
    for (j=0; j<16; j++)
    {
    Child->Memo1->Lines->Text = Child->Memo1->Lines->Text + IntToHex(InputData[i*16+j],2) + " ";
    if (j==7)
    Child->Memo1->Lines->Text = Child->Memo1->Lines->Text + "- ";
    }
    for (j=0; j<16; j++)
    {
    b = InputData[i*16+j];
    if (b < ' ' | b > 'z') b = '.'; //test czy bajt jest poprawnym ASCII
    Child->Memo1->Lines->Text = Child->Memo1->Lines->Text + char(b);
    }
    Child->Memo1->Lines->Text = Child->Memo1->Lines->Text +" " + "\n";
    }
    }

    Stworzyłem sobie MDIChild i tam wstawiłem do Child->Memo1. Działa tylko nie mogę poradzić sobie z przyporządkowaniem InputData do OpenDialog. Może to banalnie proste ale ja jestem początkującym programistą więc się nie dziw.
  • REKLAMA
  • #10 264632
    ElGregor
    Poziom 23  
    Posty: 654
    Pomógł: 2
    Ocena: 56
    Oto funkcja załadowania zawartości pliku do tablicy InputData. Dołącz ją do swojego programu. Jeśli chcesz dodatkowo kontrolować ewentualne błędy (plik za krótki, brak pliku, brak dostępu do pliku itp.) to daj znać, dopiszę sprawdzanie wyjątków.
      int handle;
    
      if (OpenDialog1->Execute())
      {
        handle = FileOpen(OpenDialog1->FileName, fmOpenRead);
        FileRead(handle, InputData, 512);
        FileClose(handle);
      }
  • #11 265676
    pietrek_pl
    Poziom 19  
    Posty: 402
    Pomógł: 23
    Ocena: 46
    Cześć.
    Mam jeszcze kilka pytań. Jak kasować zawartość tablicy przed każdym odczytem, ewentualnie wypełniać ją FF lub 00. Po zwiększeniu tablicy do 4096 bardzo długo trwa zamiana na format szesnastkowy. Czy nie dało by się użyć innej funkcji żeby to przyspieszyć?
  • #12 266331
    ElGregor
    Poziom 23  
    Posty: 654
    Pomógł: 2
    Ocena: 56
    To nie sama funkcja konwersji jest wolna, tylko przy dodawaniu każdej liczby odwołujesz się do komponentu Memo, a windows modyfikując go traci cenny czas. Najlepszą metodą przyśpieszenia będzie po prostu wygenerowanie całego gotowego tekstu do zmiennej pomocniczej Ansi i na końcu jednorazowe przypisanie do komponentu Memo.
    Tu masz przykład:
      AnsiString Lines;     // deklaracja zmiennej pomocniczej
    
      Lines = "";
      for (i=0; i<4096/16; i++)
      {
        Lines += IntToHex(i*16,4) + " ";
        for (j=0; j<16; j++)
        {
          Lines += IntToHex(InputData[i*16+j],2) + " ";
          if (j==7)
            Lines += "- ";
        }
        for (j=0; j<16; j++)
        {
          b = InputData[i*16+j];
          if (b < ' ' | b > 'z') b = '.';   //test czy bajt jest poprawnym ASCII
          Lines += char(b);
        }
      Lines += "\n";
      }
      Memo1->Lines->Text = Lines;
    }
    

    Jeśli chodzi o kasowanie tablicy przed odczytem, to jest to niepotrzebne ponieważ odczytane dane "zamażą" poprzednie wartości i w tablicy będą nowe, odczytane z pliku. Jeśli jednak odczytany plik jest krótszy od długości tablicy, "z tyłu" mogą zostać stare niezmienione wartości. Do inicjacji tablicy wystarczy zwykła pętla:
    for (int i = 0; i<4096; i++)
      InputData[i] = 0;

Podsumowanie tematu

✨ Dyskusja dotyczy problemu wyświetlania danych binarnych z pliku *.bin w formacie szesnastkowym (HEX) w środowisku C++Builder 5. Zaproponowano dwie metody konwersji bajtów na format HEX: ręczne przeliczenie każdego bajtu na dwa znaki HEX za pomocą operacji dzielenia i reszty z dzielenia, oraz wykorzystanie wbudowanej funkcji IntToHex, która konwertuje liczbę całkowitą na tekst w formacie HEX z określoną liczbą cyfr. Przedstawiono przykładowe fragmenty kodu, które odczytują dane z pliku do tablicy bajtów, a następnie wyświetlają je w formacie przypominającym klasyczny heksadecymalny dump, z podziałem na offsety, wartości HEX oraz odpowiadające im znaki ASCII (lub '.' dla znaków nieczytelnych). Zwrócono uwagę na optymalizację wydajności poprzez budowanie całego tekstu w zmiennej pomocniczej typu AnsiString i jednorazowe przypisanie go do komponentu Memo, zamiast wielokrotnego modyfikowania komponentu w pętli. Poruszono także kwestie zerowania lub wypełniania tablicy danymi przed odczytem oraz skalowania do większych rozmiarów (np. 4096 bajtów). Całość opiera się na standardowych funkcjach i komponentach C++Builder 5, takich jak Label, Memo, IntToHex, FileOpen, FileRead i FileClose.
Wygenerowane przez model językowy.
REKLAMA