Question

I have this defensive-programming issue that I don't really know how to solve.

I have this function that takes file path and size of table (rows / columns count) as arguments and I'm looking for better way of validating the input file. I assume that arguments of this function are always correct. size represents the "smaller side" of the table that is stored in file:

For example :

1 2 3 4 
5 6 7 8 

size = 2 is correct while

1 2 3 4 5
5 6 7 8 9

size = 2 is incorrect

I'd also like to be able to reject the files like this

1 2 3 4 5 6 7 8

size = 2 (which is accepted through fscanf)

Another type of file I'd like to be able to reject is

1 2 3
4 5 6

size = 2

As for now my only security is checking if the elements of the file are really numbers.

Here is the code I've done so far :

void import(float** table, int size, char* path)
{
    FILE* data = fopen(path, "r");
    assert(data);
    int i,j;
    int st;

    for (i=0; i<size; i++)
    {
        for(j=0; j<(size*2)-1; j++)
        {
            st = fscanf(data, "%f", &table[i][j]);
            if (!st)
            {
                printf("Error while importing the file.\n");
                fclose(data);
                return -1;
            }
        }
    }
    fclose(data);
}

I don't really where and how to start, I'm not really proficient in C and there seems to exist a lot of functions and mechanisms to do what I want but they all seem very complex and some are actually longer than the code I provided.

If anyone can point me in the right direction that'd be great.

Was it helpful?

Solution

Your for loop could look like this:

char line[1000], *token;
for (i = 0; i < size; i++) // for each line
{
    if (fgets(line, 1000, data) != NULL) // read line
    {
        token = strtok (line," ");
        for (j = 0; j < (size * 2) - 1; j++) // for each number from line
        {
            if (sscanf(token, "%f", &table[i][j]) <= 0)
            {
                // there are columns missing:
                printf("Error while importing the file.\n");
                fclose(data);
                return -1;
            }
            token = strtok (NULL," ");
        }
    }
    else
    {
        // there are rows missing:
        printf("Error while importing the file.\n");
        fclose(data);
        return -1;
    }
}

Also note that assert(data); should be replaced with something like this:

if (!data)
{
    printf("Error while openning the file [filePath=\"%s\"].\n", filePath);
    cleanExit();
}

OTHER TIPS

You can't readily detect ends of lines in scanf(), so using that directly is not going to meet your criteria.

You probably need to read entire lines (fgets() or perhaps getline()), and then process each line in turn. The line processing can use sscanf(), and you can use the %n directive too. In outline, this boils down to:

for (line_num = 0; line_num < size; line_num++)
{
    ...read line from file into buffer line, checking for EOF...
    start = line;
    for (i = 0; i < 2 * size; i++)
    {
        if (sscanf(start, "%f%n", &value, &offset) != 1)
            ...ooops - short line or non-numeric data...
        else
        {
            start += offset;
            table[line_num][i] = value;
        }
    }
}
...check that there's no clutter after the last expected line...

You could also calculate a checksum of the entire file. The question is how serious you are about it. It's easy to create an xor checksum, but it's not really safe against collisions. The best is probably to use something like sha-1 if it's important.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top