tags:

views:

192

answers:

2

Hi, I wish to get strings from the buffer of raw bytes in the memory, will work well?

static int in = 0; 

void *loadFile (FILE *fp) 
{
    fseek (fp, 0L, SEEK_END);
    size_t size = ftell (fp);
    fseek (fp, 0L, SEEK_SET); 


    char *buf = malloc (sizeof(char) * size);
    if (!buf)
        return NULL;

    if (fread (buf, sizeof(char), size, fp) != size) {
        free (buf);
        return NULL;
    }

    return buf;
}

char *getString (void *buf) 
{
    char *l_buf = buf;

    int i, j, num;
    char *string = NULL;

    for (i = in; l_buf[i] == '\n' || l_buf[i] == '\r'; i++); 

    for (j = i; l_buf[j] != '\n' && l_buf[j] != '\r'; j++); 

    num = j - i;
    string = malloc (sizeof(char) * (num + 1));

    if (!string) 
        return NULL;

    in = j;

    strncpy (string, &l_buf[i], num);
    string[num] = '\0';

    return string;
}
+1  A: 

All references to buf[i] should be l_buf[i]. buf[i] is indexing from a void pointer (not what you want), but l_buf [i] is indexing from a char pointer.

Scott Thomson
Oh, this is a typing error
Ariel
+1  A: 

I believe there is at least one problem with the solution as proposed and that is there is no check to ensure you don't run off the end of the memory buffer in getString(). So one way to avoid this in your read code would be to add an explicit NULL to the end of the buffer like so

char *buf = malloc (sizeof(char) * (size + 1));
if (!buf)
   return NULL;

if (fread (buf, sizeof(char), size, fp) != size) {
    free (buf);
    return NULL;
}
buf[size] = `\0`;

And then in your string extraction function add the a NULL check to the line termination tests, something like this:

for (i = in; l_buf[i] != '\0' && (l_buf[i] == '\n' || l_buf[i] == '\r'); i++);
if (l_buf[i] == '\0') {
    /* Never saw the start of a line before the buffer ran out */
    return NULL;
}

for (j = i; l_buf[i] != '\0' && l_buf[j] != '\n' && l_buf[j] != '\r'; j++);
if (i == j) {
    return NULL;
}

There is another potential problem but as you didn't say whether you were running on UNIX or Windows or cared about portability here I can't be sure. The proposed code doesn't deal with line terminations that include both `\r' and '\n'.

I would also suggest to make the function re-entrant by replacing the global start position index with a parameter like so:

char *getString (void *buf, int *in) { ...

Then just update that pointer in getString() like so:

*in = j;
bjg
Thank you very much! I take care of Win, Unix, Mac - you write: the proposed code doesn't deal with line terminations that include both `\r' and '\n'. Why? These symbols follow char by char in the memory, thus we can check the first one of them only, isn't it?
Ariel
What I was highlighting was that in the case where you have double character line terminations (such as on Windows) then if you only detect the first of these (as in the code above) then the first character of the string you return will contain the second termination character. So you need to check if there is a second termination character and then "step over" it before doing the strncpy()
bjg
The first `for ()` checks whether there is end-of-line character in the beginning of the buffer
Ariel