-3

OK. So i have this code i written, and all it does is print 16 hexadecimal values and then prints 16 characters then prints a newline for the next row. In the for loop i noticed that i had to do it a certain way to get it to print anything above 127, why i do not know, that is why i am here asking you.

On top of that does anyone have any pointers about using cout with hex? because i would had to of imported an additional module just to set the width of cout to 2.

This code was just done for practice, i wanted to output to look like it does in the hex editor HxD. I think i can use just one string without having to copy the same values twice in the string declaration.

But yes, any pointers or criticisms please dont hold back.

#include <iostream>
#include <fstream>
#include <string>

#define SIZE 0x830

using namespace std;

int main(int argc, char * argv[])
{

    int i, j, k;

    ifstream dump(argv[1], ios::binary);

    char* buffer = new char[SIZE];

    if (dump.is_open())
    {
        dump.read(buffer, SIZE);
        dump.close();
    }
    else
    {
        cout << "no success :(\n";
        exit(0);
    }

    std::string my_hex;
    std::string my_char;

    for (int i = 0; i < SIZE; i++)
    {
        my_hex += buffer[i];
        my_char += buffer[i];
    }

    for (int j = 0; j <= 2095; j++)  //j is the position we are in the loop, which means that j also equals current character.
    {

        if ((j % 16 == 0) && (j != 0)) //if j is divisible by 16 and does not equal 0 then enter this if block, otherwise just print my_hex[j]
        {

            for (k = 0; k <= 15; k++) 
            { //handle regular characters

                if ((my_char[(j + k) - 16] >= 0) && (my_char[(j + k) - 16] <= 31) || (my_char[(j + k)] == 255))
                { // this checks if the value is lower than 31 or equal to 255, either which can have a '.' printed in its place.
                    cout << ".";
                }
                else if ((my_char[(j + k) - 16] >= 32) && (my_char[(j + k) - 16] <= 127))
                { //if value is greater than or equal to 32 or equal to or less than 127 it will print that character, remember to print the correct character. we must go back to the beginning of the string with - 16.
                    cout << my_char[(j + k) - 16];
                }
                else
                {
                    cout << my_char[(j + k) - 16];  //prints everything above 127
                };

            }
            cout << "\n";
        }
        printf("%02x ", (unsigned char) my_hex[j]); //print hexadecimal values of characters
    }
    dump.close();
    return 0;
}

If you think you know a better way, then please by all means enlighten me :) *i had to swap code page in cmd to 1252 (ANSI) for character output to look right as compared to HxD.

james28909
  • 554
  • 2
  • 9
  • 20
  • 1
    Is this `std::cout << std::hex << 19 << std::endl;` what you are looking for? – Ahmad Siavashi Aug 11 '17 at 19:44
  • 1
    What's wrong about using `std::hex`?? – user0042 Aug 11 '17 at 19:44
  • you mean in the forloop conditionals. as in instead of `for(i = 0; i >= 2095; i++)` to instead do something like `for(i = 0; i >= length.my_hex; i++)`? – james28909 Aug 11 '17 at 19:44
  • 2
    Good odds that char is a signed type on your system. Try using `unsigned char`. – user4581301 Aug 11 '17 at 19:45
  • see that is another problem i have is figuring out data types. and the difference in signed and unsigned and how that even effects the data. – james28909 Aug 11 '17 at 19:47
  • for any one who tries to run this, you forgot to add #include for your exit(0). – BlooB Aug 11 '17 at 19:47
  • 1
    Popping your code into my IDE for a quick indenting fix has the compiler screaming bloody blue murder about potential bracket ambiguities. I'd turn up the compiler's warning level and address the complaints if I were you. – user4581301 Aug 11 '17 at 19:48
  • 1
    An off topic note on `exit(0)`. Not much point to it in the `main` function. Save yourself the hassle and just `return 0;` – user4581301 Aug 11 '17 at 19:50
  • Aren't the variables `i` and `j` pointless? – Arnav Borborah Aug 11 '17 at 19:51
  • 1
    please add some comments in your code, that way people can follow your code eaisier – BlooB Aug 11 '17 at 19:53
  • 1
    See `std::isprint`, which tests if a character is printable. – Thomas Matthews Aug 11 '17 at 20:03
  • 1
    What location is `my_char[(j + k) - 16]` referring to when `j` and `k` are zero? Usually negative indices are not a good thing. – Thomas Matthews Aug 11 '17 at 20:05
  • ill add some comments, but all it does is prints 16 hexadecimal chars and if the iterator is divisible by 16 then it prints 16 regular characters and a new line. the weird cout problem is in the if (i%16 == 0 block). if i remove `cout << "."` or change it in any way, it wont print anything above 127. also the `i` iterator loops through the original string. the `j` iterator indexes the my_char string and allow to print the values corresponding with the 16 hexadecimal characters. i think this can be done without the second my_char string, but i just havent done it. – james28909 Aug 11 '17 at 20:09
  • 1
    What's the difference between `my_hex` and `my_char`? – Thomas Matthews Aug 11 '17 at 20:11
  • @thomasmathews, it corresponds to the current character in my_hex. see what it does is loops through 0-2095. then if `j` is divisible by 16 but does not equal 0, THEN... it loops 0-15 printing out the characters and a new line. if it is not divisible by 16 and or equals 0, then it just prints the hexadecimal. also `my char[(j+k)] - 16` doesnt refer to anything if j equals 0. thats what `if ((j % 16 == 0) && (j != 0))` covers :) – james28909 Aug 11 '17 at 20:16
  • @thomasmathews one of those strings can be done away with. i just couldnt figure it out yet. – james28909 Aug 11 '17 at 20:17
  • also i would like to add, down voting and not commenting is frowned upon, if you down vote the question, then please comment as to why you down voted and how you would fix it. downvotes from people who do not comment are useless. – james28909 Aug 11 '17 at 20:45
  • 1
    This doesn't address the question, but instead of hard-coding all those magic numbers (which are, presumably, ASCII values), read about `std::isprint`. – Pete Becker Aug 11 '17 at 21:14
  • 1
    It's hard to line up downvotes and comments. Sometimes the reason the question is being downvoted has already been commented upon. – user4581301 Aug 11 '17 at 21:21

1 Answers1

3

I believe your code is too complicated.

char * p_row = &buffer[0];

const unsigned int BYTES_PER_ROW = 16;
unsigned int byte_count = 0;
while (byte_count < size)
{
    // Print the offset for the row, in hex
    const size_t offset = (size_t)(p_row - &buffer[0]);
    std::cout << std::hex << std::fill('0') << std::setw(6)
              << offset;
    std::cout << "   ";

    // Print hex values for each byte in the row
    for (unsigned int i = 0; i < BYTES_PER_ROW; ++i)
    {
      const unsigned int byte = (uint8_t)(p_row[i]);
      std::cout << std::hex << std::fill('0') << std::setw(2)
                << byte;
      if (i == 8)
      {
         std::cout << "  ";
      }
    }
    // Print ASCII values for printable characters or '.'
    std::cout << "      ";
    for (unsigned int i = 0; i < BYTES_PER_ROW; ++i)
    {
       char c = p[i];
       if (!isprint(c))
       {
         c = '.';
       }
       std::cout << c;
    }
    std::cout << "\n";
    p += BYTES_PER_ROW;
    byte_count += BYTES_PER_ROW;
}

In the above code, the offset is printed first.
Next, the row is printed in 2 digit hexadecimal format.
Finally, the row is printed as printable characters or '.'.

The buffer pointer and byte count are incremented by the number of bytes per row.

The above code does not account for rows that are not of BYTES_PER_ROW length. This is an easy fix and left as an exercise for the OP. Hint: use istream::gcount to get the number of bytes actually read from the file.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • thank you. i will examine this code to the fullest extent of the law. im not up to par on using `*` and `&`. if you have some easy terminology to help me understand i would much appreciate it! – james28909 Aug 11 '17 at 20:37
  • what i am wanting to do is print any character that is printable and '.' for the ones that arent. but lining up the data in output was tricky (for me lol) – james28909 Aug 11 '17 at 20:38
  • Use your favorite reference and look up `isprint`. Your `if` statements can be replaced by a call to `isprint`. – Thomas Matthews Aug 11 '17 at 20:49
  • you know, i had already looked but the output i was getting did not meet the expected output. im sure it had everything to do with me though and not the isprint function. also, the function isprint, is there a certain range defined that "isprint"able? how does isprint know if the character is printable? – james28909 Aug 11 '17 at 21:11
  • 1
    @james28909 There's a lot of behind the scenes magic in the answer to that last question. I'm going to link you to some [old school `ctype` `isprint` documentation](http://en.cppreference.com/w/cpp/string/byte/isprint) and to the [modern, `locale` `isprint` documentation](http://en.cppreference.com/w/cpp/locale/isprint). Probably best if you start by getting a grasp on the old one first. New one is more versatile, but as a result the magic goes deeper. – user4581301 Aug 11 '17 at 21:20