0

Good evening, I'm new to C++ and encountered a problem that I wasn't able to solve despite reading numerous pages here. I've got a file with hexvalues that need to be read and compressed, then written in a new file. An example sequence looks like this:

C9 CB FF 01 06 (each byte [8 bit] represent a number)

Compression starts with the first number, then only writing the difference to the next number (differences are a nibble [4 bit]). Example from C9 to CB: difference = 2. If the difference is greater than 7, thus can't be represented by a nibble, we use a 0x8 to mark a new start. 0xFF-0xCB > 7 so the sequence would look like this (entire compressed code):

C9 28 FF 15 (mixture of entire bytes (0xC9 and 0xFF) representing numbers and nibbles representing differences to the next number. Now to my problem. I'm using fstream and put to write bytes to a new file, nibbles are stored to combine with an other nibble to a byte which can be written to the file. However it only works with bytes smaller than 128 so I can't write values greater than 0x7F into a file. I prepared a file with notepad++ starting with the value 0xFF - reading that value works great but dest.put(source.get()); doesn't in that specific case. How can I work with (signed) nibbles [for negative differences] and binary presentations of numbers in C++? By the way using negative numbers in file.put() results in strange behavior as 2 bytes are written rather than one. Here's my code, I hope you understand my problem and I really appreciate your help

int lastValue = s.get();
d.put((char)lastValue);
char highNibble = 0;
bool nibbleSet = false;
int diff = 0;
for (int c = s.get(); c != -1; c = s.get()) {
    diff = (char)((unsigned char)c - (unsigned char)lastValue);
    if (abs(diff) > 7) {
        if (nibbleSet) {
            d.put(highNibble << 4 | 8);
            d.put((char)c);
            nibbleSet = false;
        }
        else {
            cout << (8 << 4 | (c & 0xF0) >> 4) << endl;
            d.put(8 << 4 | (c & 0xF0) >> 4);
            highNibble = c & 0x0F;
            nibbleSet = true;
        }
    }
    else {
        if (nibbleSet) {
            d.put(((char)highNibble << 4) & 0xF0 | ((char)diff) & 0x0F);
            nibbleSet = false;
        }
        else {
            highNibble = (char)diff;
            nibbleSet = true;
        }
    }
    lastValue = c;
}
neophoenix
  • 66
  • 6
  • 2
    The minimum size you can write to a file in C++, or an any language I'm familiar with, is 8 bits, at least on modern architectures (yes, I used to work on a DEC-10). To write anything smaller, you would have to buffer the smaller value up, with other small values, until it filled 8 bits, and then write that. –  Mar 06 '17 at 00:01
  • 1
    What type is `d`? How does it get its value? Also, why are you using `char`, which is probably signed, instead of `unsigned char`, which is guaranteed not to be? – David Schwartz Mar 06 '17 at 00:04
  • @NeilButterworth yes I try to buffer smaller values up until it reaches 8 bits (see highNibble as buffer) but put expects a char and doesn't accept values over 127 – neophoenix Mar 06 '17 at 06:41
  • @DavidSchwartz s is the source file (reading) while d is the destination file (writing). Both are type fstream. Differences can be negative too C9 - CB = -2 so I'd need char, don't I? – neophoenix Mar 06 '17 at 06:44
  • @neophoenix What do you want to write into the file for `C9 - CB`? Do you want to write `-2` to the file? If so, then you have a serious problem. The range from `00` to `FF` inclusive covers every possible value of a byte -- there's no value left over to encode `-2`. – David Schwartz Mar 06 '17 at 06:49
  • @David Schwartz yes, thats why I want toll use signed nibbles with a range of -8 to 7. A Byte 00-FF represents 2 signed nibbles or one signed nibble and half of an unsigned byte – neophoenix Mar 06 '17 at 08:32
  • Okay, so your input is unsigned but your output is signed. So you should use a larger, signed type to hold your intermediary values. Perhaps: `diff = (int)c - (int)lastValue;`. Also, `c` and `lastValue` should be `unsigned char`. This way, there are no overflows or underflows and you treat the input correctly as unsigned bytes. – David Schwartz Mar 06 '17 at 08:34
  • To represent -2 the nibble would be 0xE so the Byte would be 0xEv or 0xVE (V is an other signed nibble or part of a signed Byte) – neophoenix Mar 06 '17 at 08:41
  • No, the difference might be an under or overflow (difference between 3 and 254 for example is 5). – neophoenix Mar 06 '17 at 08:43
  • @neophoenix That will not underflow if you cast to `int` as I suggested. – David Schwartz Mar 06 '17 at 08:49
  • Yes, lastValue should be unsigned you are right. But casting Both C and lastValue as int will not make diff over or underflow - it is supposed though in case lastValue is like 253 and C is like 2. Otherwise the difference would be -251. It should be 4 in that case. Or do i understand it incorrectly? May Code for getting differences works as it is supposed to, writing values like 0xFF or any other greater than 127 into a file with put doesnt – neophoenix Mar 06 '17 at 10:35

0 Answers0