Lior
Lior

Reputation: 6051

fgetc stops when recognizing new line (\n)

I have this code:

while( (cCurrent = fgetc(fp)) != EOF)
{

}

The problem is, when it hits a new line it stops reading.

What would be a good way to ignore the newline character?

Edit:

I'm trying to create a file crypter. It is able to encrypt the file, but the decrypt process won't work. It works till the end of the first line, but it won't continue to the next characters in the file.

For example, for the text file:

Foo  
Bar

After the encryption the result is:

Xu||Gb|t

After the decryption the result is:

FooRqb

I concluded that the new line char was the problem. maybe it wasn't.

My code is:

/* check if the file is openable */
if( (fp = fopen(szFileName, "r+")) != NULL )
{
    /* save current position */
    currentPos = ftell(fp);
    /* get the current byte and check if it is EOF, if not then loop */
    while( (cCurrent = fgetc(fp)) != EOF)
    {
        /* XOR it */
        cCurrent ^= 0x10;
        /* take the position indicator back to the last position before read byte */
        fseek(fp, currentPos, SEEK_SET);
        /* set the current byte */
        fputc(cCurrent, fp);
        /* reset stream for next read operation */
        fseek(fp, 0L, SEEK_CUR);
        /* save current position */
        currentPos = ftell(fp);
    }

Upvotes: 4

Views: 17432

Answers (4)

prprcupofcoffee
prprcupofcoffee

Reputation: 2970

On Windows, lines in text files are separated by \r\n, not just \n, and files are opened by default in "text" mode, which automatically translates \r\n to \n when reading the file (see fopen in Visual Studio 2012).

Since you're interpreting your file as a sequence of bytes (because of the XOR operation), you don't want this behavior - each time there is a line ending, you're losing a byte of data. You should open your file in "binary" mode to suppress this behavior:

fp = fopen(szFileName, "rb+")

This will also suppress the behavior noted by @Mike where reading a \x1A character is interpreted as the end of file.

Upvotes: 4

Mike
Mike

Reputation: 49403

It took me a while, but I finally got what you're trying to do.

Input file:

Hello

encrypt by running your code:

Xu||(non displayable character)

Decrypt by running your code again:

Hello

So how this works:

0x48 XOR 0x10 = 0100 1000 (H)---+
                0001 0000       |
                ---------       V
                0101 1000 = 58 (X)

0x58 XOR 0x10 = 0101 1000 (X)---+
                0001 0000       |
                ---------       V
                0100 1000 = 48 (H)

The problem comes in with you're working with the new line character '\n' which is 0xA16

Input file:

Hello
You

This works fine up until the '\n' then we get new line:

0xA XOR 0x10 =  0000 1010 ('\n')---+
                0001 0000          |
                ---------          V
                0001 1010 = 1A (substitute character)

The substitute character In DOS operating systems, this character is used to indicate the end of a file (EOF)

So this fails because you're working on Windows. So you need to do special checking for the '\n' case in your encryption/decryption and not blindly XOR it.

One easy fix, you could simply do something like:

while( (cCurrent = fgetc(fp)) != EOF)
{
    /* XOR it if it's not a '\n'*/
    if(cCurrent != '\n')
      cCurrent ^= 0x10;

Upvotes: 7

Jonathan Wood
Jonathan Wood

Reputation: 67193

This is not the correct behavior for fgetc().

Your second code snippet is puzzling as it does in fact break when you hit a newline. So how that resolves the issue is a mystery to me.

I suspect you have your logic mixed up a little.

Upvotes: 0

iabdalkader
iabdalkader

Reputation: 17312

fgetc shouldn't stop at a newline character, only at EOF, from man fgetc(3):

fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.

If you however, write it like this:

while( (cCurrent = fgetc(fp)) != '\n' && cCurrent != EOF)

It will stop at the newline character, so the first one is correct:

while( (cCurrent = fgetc(fp)) != EOF)

Upvotes: 2

Related Questions