Hey guys,

I'm parsing this WaveFront .obj file, still (for those that have read the previous post), but it has some really weird error in it that I haven't seen in a program before.

The parsing algorithm starts out like this:

Open the file in textmode.
Get filesize
Allocate buffer with calloc, size: filesize + 1
Read file in buffer
Count the lines

Now, the filesize is correct, and reading goes okay too: ferror() doesn't report any errors.

The linecount is, however, off! :( I'm using this code:

printf("Counting lines and determining maximum length...");
  int maxLen, lenCount;
  int lines;

  for (i = lines = lenCount = maxLen = 0; i <= fileSize; i++){
    if (data[i] == '\n'){
      lines++;
      lenCount++;
      if(lenCount > maxLen) maxLen = lenCount;
      lenCount = 0;
    }
    lenCount++;
  }

  printf("Counted %d lines, maximum length: %d\n", lines, maxLen);

In short:

current char a newline?
Yes: 
  add one to lines and chars
  update max string length
No: 
  add one to chars

Well, I couldn't think that that piece of code is wrong since it's so simple. Besides, it worked with numerous files and I've used that same code in the past. But the linecount is off. So I output char *data. Just to make sure, the output (cut away a lot, it's a 458KB file ;))

f 2483//3522 2134//3498 2028//3437
f 2527//3523 2028//3437 2906//3436
f 2555//3524 2527//3523 2906//3436
f 2556//3525 2555//3524 2906//3436
f 2558//3526 2556//3525 2906//3436
f 2558//3526 2906//3436 2560//3515
f 2527//3523 2483//3522 2028//3437
//3525 2906//3436

f 2558//3526 2906//3436 2560//3515

f 2527//3523 2483//3522 2028//3437

41 2860//3237 2863//3240

f 2800//3183 2813//3184 2861//3238

f 2865//3242 2861//3238 2813//3184

f 2861//3238 2865//3242 2862//3239

f 2866//3243 2862//3239 2865//3242

f 2813//3184 2818//3191 2865//3242

f 2867//3244 2865//3242 2818//3191

f 2865//3242 2867//3244 2866//3243

f 2868//3245 2866//3243 2867//3244

While it SHOULD have been:

f 2483//3522 2134//3498 2028//3437
f 2527//3523 2028//3437 2906//3436
f 2555//3524 2527//3523 2906//3436
f 2556//3525 2555//3524 2906//3436
f 2558//3526 2556//3525 2906//3436
f 2558//3526 2906//3436 2560//3515
f 2527//3523 2483//3522 2028//3437

For some reason I get more data then there is! The lines it reads in are correct, but it keeps reading! I know the buffer has plenty of data to store it all, I've changed the size (filesize+1) to filesize+200, +800, hell, even +2000, just to make sure. It's calloc'ed, so it's cleared...

I don't know what to try anymore. Any help is greatly appreciated, it's driving me mad.

Thanks in advance,
Nick

Oh, here's the code by the way. It looks like a lot of code, but the error is in the first 40 lines.

loadObj:

int entity::loadObj(const char *loc,\
            float **retvertices, float **retgouraudnormals,\
            int **rettriangleindex, int **retquadindex,\
            unsigned int *quadcount, unsigned int *trianglecount){

  float *vertices, *gouraudnormals;
  int *triangleindex, *quadindex;
  float *normals, *verttext;
  int *trianglenormals, *quadnormals;

  clock_t startTime = clock();
  int fileSize = 0;
  int n, i, j;
  printf("Opening file: \"%s\"\n", loc);

  FILE *pFile = fopen(loc, "r");
  if(pFile == NULL){
      dbgError("fopen()");
      exit(1);
  }

  fseek(pFile, 0, SEEK_END);
  fileSize = ftell(pFile);
  rewind(pFile);

  char *data = (char*) calloc(sizeof(char), fileSize + 20);

  fread(data, 1, fileSize, pFile);
  if(ferror(pFile)){
      dbgError("fread()");
      exit(1);
  }
  puts(data);

  fclose(pFile);

  printf("Done reading, parsing file now.\n");
  /*You can return here, the "wrong" data is now written to stdout*/
  return 123;
  /*Or you can continue and let it load all the way*/

  TIMEELAPSED

  printf("Removing #IND if there...");
  char *pIND = data;
  n = 0;
  while(1){
    pIND = strstr(pIND, "#IND");
    if(pIND != NULL){
      memcpy(pIND, "0000", sizeof(char) * 4);
      n++;
    }
    else break;
  }
  printf("Removed %d #INDs\n", n);
  TIMEELAPSED

  printf("Counting lines and determining maximum length...");
  int maxLen, lenCount;
  int lines;

  for (i = lines = lenCount = maxLen = 0; i <= fileSize; i++){
    if (data[i] == '\n'){
      lines++;
      lenCount++;
      if(lenCount > maxLen) maxLen = lenCount;
      lenCount = 0;
    }
    lenCount++;
  }

  printf("Counted %d lines, maximum length: %d\n", lines, maxLen);
  TIMEELAPSED

  printf("Allocating %d strings of %d chars...", lines, maxLen);
  char **parsedText = (char**) calloc(sizeof(char*), lines);
  for(n = 0; n < lines; n++){
    parsedText[n] = (char*) malloc(sizeof(char) * maxLen);
    if (parsedText[n] == NULL){
      printf("Malloc failed to allocate %d bytes for parsedText[%d].\n", maxLen, n);
      return -1;
    }
  }
  printf("Done\n");
  TIMEELAPSED

  printf("Reading in 2D array...");
  for(i = n = j = 0; n < lines; i++){
    if(data[i] == '\n'){
      parsedText[n][j] = '\0';
      puts(parsedText[n]);

      n++;
      j = 0;
      continue;
    }
    //printf("parsedText[%d][%d] = textTree[%d] = %c\n", n, j, i, data[i]);
    parsedText[n][j] = data[i];
    j++;
  }
  printf("Done\n");
  TIMEELAPSED

  //free the data, we don't need it anymore since it's stored in parsedText
  free(data);


  printf("Counting...");

  int vertlines, normallines, facelines, texturelines;
  vertlines = normallines = facelines = texturelines = 0;

  unsigned int faceverts, maxFaceverts, trianglecnt, quadcnt;
  faceverts = maxFaceverts = trianglecnt = quadcnt = 0;

  //stores for every face line how many verts it has.
  int *facevertcnt = (int*)calloc(sizeof(int), lines);
  for(i = 0; i < lines; i++){
    if(parsedText[i][0] == '#') continue;

    if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){
      vertlines++;
    }

    else if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){
      normallines++;
    }

    else if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){
      facelines++;
      for(n = 2; !isdigit(parsedText[i][n]); n++);
      faceverts = countSpaces(&parsedText[i][n]);
      if(faceverts == 2){
        trianglecnt++;
        //printf("triangle: %s\n", parsedText[i]);
      }
      else if(faceverts == 3){
        quadcnt++;
        //printf("quad: %s", parsedText[i]);
      }
      if(faceverts > maxFaceverts) maxFaceverts = faceverts;
      facevertcnt[i] = faceverts;
      //getchar();
    }

    else if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){
      texturelines++;
    }

    else{
        printf("WARNING: Line not supported: %s\n", parsedText[i]);
    }
  }

  int vertvals = vertlines * 3;
  int normalvals = normallines * 3;
  int texturevals = texturelines * 2;
  int triangleverts = trianglecnt * 3;
  int quadverts = quadcnt * 4;

  *trianglecount = trianglecnt;
  *quadcount = quadcnt;

  printf("Counted:\n\t%d vertices\n\t%d normals\n\t%d faces (%d triangles, %d quads)\n", vertlines, normallines, facelines, trianglecnt, quadcnt);
  TIMEELAPSED
  if(maxFaceverts > 4){
    printf("WARNING:\n  Model won't be imported correctly due to polygons with more than 4 vertices.\n");
  }

  printf("Allocating memory for data...");
  vertices = (float*)calloc(sizeof(float), vertvals);
  normals = (float*)calloc(sizeof(float), normalvals);
  verttext = (float*)calloc(sizeof(float), texturevals);
  triangleindex = (int*)calloc(sizeof(int), triangleverts);
  trianglenormals = (int*)calloc(sizeof(int), triangleverts);

  quadindex = (int*)calloc(sizeof(int), quadverts);
  quadnormals = (int*)calloc(sizeof(int), quadverts);

  if(vertices == NULL || normals == NULL || verttext == NULL || triangleindex == NULL || trianglenormals == NULL || quadindex == NULL || quadnormals == NULL){
    printf("Failed to allocate enough memory, exiting...\n");
    return -1;
  }


  int vertcount, normalcount, textcount, tricnt, quacnt;

  printf("Done\n");
  TIMEELAPSED

  printf("Reading in data...");
  for(vertcount = normalcount = textcount = tricnt = quacnt = i = 0; i < lines; i++){
    //comment
    if(parsedText[i][0] == '#') continue;
    if(parsedText[i][0] == ' ') continue;

    //vertex
    if(vertlines)
    if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){
      sscanf(&parsedText[i][2], "%f%f%f", (vertices+vertcount), (vertices+vertcount+1), (vertices+vertcount+2));
      vertcount += 3;
    }

    //normal
    if(normallines)
    if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){
      sscanf(&parsedText[i][2], "%f%f%f", (normals+normalcount), (normals+normalcount+1), (normals+normalcount+2));
      normalcount += 3;
    }

    //texture
    if(texturelines)
    if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){
      sscanf(&parsedText[i][2], "%f%f", (verttext+textcount), (verttext+textcount+1));
      textcount += 2;
    }

    //faces
    if(trianglecnt || quadcnt)
    if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){
      if(facevertcnt[i] == 2){
        //skip all leading spaces
        for(n = 2; isspace(parsedText[i][n]); n++);
        //read in the vertexnr
        sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+1));
        n++;

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+1));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+2));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+2));
        }
        for(j = 0; j < 3; j++){
          //-4 on line 4 becomes 0.
          if(triangleindex[tricnt+j] < 0){
            triangleindex[tricnt+j] = i - triangleindex[tricnt+j];
          }
          else{
            triangleindex[tricnt+j]--;
            trianglenormals[tricnt+j]--;
          }
        }

        tricnt += 3;
      }
      if(facevertcnt[i] == 3){
        //skip all leading spaces
        for(n = 2; isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+1));
        n++;

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+1));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+2));
        n++;

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+2));
        }

        for(;!isspace(parsedText[i][n]); n++);
        sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+3));

        if(normallines){
          //skip 2 slashes
          for(; parsedText[i][n] != '/'; n++); n++;
          for(; parsedText[i][n] != '/'; n++); n++;
          //read in the normalnr
          sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+3));
        }
        for(j = 0; j < 4; j++){
          //-4 on line 4 becomes 0.
          if(quadindex[quacnt+j] < 0){
            quadindex[quacnt+j] = i - quadindex[quacnt+j];
          }
          quadindex[quacnt+j]--;
          quadnormals[quacnt+j]--;
        }

        quacnt += 4;
      }
    }
  }
  printf("Done\n");
  TIMEELAPSED

  if(normallines){
    printf("Calculating Gouraud normals for each vertex...");
    gouraudnormals = (float*)calloc(sizeof(float), vertvals);
    float normalx, normaly, normalz;
    if(trianglecnt != 0){
      //printf("::DBG:: calcing trianglenormals\n");
      for(i = 0; i < triangleverts; i++){
        //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", triangleindex[i]*3, normalvals, trianglenormals[i]*3);
        normalx = normals[trianglenormals[i]*3];
        normaly = normals[trianglenormals[i]*3+1];
        normalz = normals[trianglenormals[i]*3+2];

        gouraudnormals[triangleindex[i]*3]   += normalx;
        gouraudnormals[triangleindex[i]*3+1] += normaly;
        gouraudnormals[triangleindex[i]*3+2] += normalz;
      }
    }

    if(quadcnt != 0){
      //printf("::DBG:: calcing quadnormals\n");
      for(i = 0; i < quadverts; i++){
        //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", quadindex[i]*3, vertvals, quadnormals[i]*3);
        normalx = normals[quadnormals[i]*3];
        normaly = normals[quadnormals[i]*3+1];
        normalz = normals[quadnormals[i]*3+2];

        gouraudnormals[quadindex[i]*3]   += normalx;
        gouraudnormals[quadindex[i]*3+1] += normaly;
        gouraudnormals[quadindex[i]*3+2] += normalz;
      }
    }
    printf("Done\n");
    TIMEELAPSED

    printf("Normalizing normals...");
    for(i = 0; i < normalvals; i += 3){
      normalx = fabs(gouraudnormals[i]);
      normaly = fabs(gouraudnormals[i+1]);
      normalz = fabs(gouraudnormals[i+2]);

      float max = normalx;
      if (normaly > max) max = normaly;
      if (normalz > max) max = normalz;

      //normalize
      if(max != 0){
        gouraudnormals[i]   /= max;
        gouraudnormals[i+1] /= max;
        gouraudnormals[i+2] /= max;
      }
    }

    printf("Done\n");
    TIMEELAPSED
  }
  else{
    printf("No normals detected! This version doesn't calculate normals, too lazy. :(\n");
  }

/*   for(n = 0; n < vertvals; n += 3){
    printf("v %f %f %f\n", vertices[n], vertices[n+1], vertices[n+2]);
  } */

/*   for(n = 0; n < normalvals; n += 3){
    printf("vn[%d] %f %f %f\n", n/3, normals[n], normals[n+1], normals[n+2]);
  } */

/*
  for(n = 0; n < texturevals; n += 2){
    printf("vt %f %f\n", verttext[n], verttext[n+1]);
  } */

/*
  for(n = 0; n < triangleverts; n += 3){
    printf("triangle: %d %d %d\n\t"
           "Normals: %d %d %d\n",\
           triangleindex[n], triangleindex[n+1], triangleindex[n+2],\
           trianglenormals[n], trianglenormals[n+1], trianglenormals[n+2]);
  } */

/*   for(n = 0; n < quadverts; n += 4){
    printf("Quad: %d %d %d %d\n\t"
           "Normals: %d %d %d %d\n",\
           quadindex[n], quadindex[n+1], quadindex[n+2], quadindex[n+3],\
           quadnormals[n], quadnormals[n+1], quadnormals[n+2], quadnormals[n+3]);
  } */

/*   if(normallines)
  for(n = 0; n < vertlines; n++){
    printf("Normals for v[%d]: %f %f %f\n", n, gouraudnormals[n*3], gouraudnormals[n*3+1], gouraudnormals[n*3+2]);
  } */

  printf("File succesfully loaded, returning.\n");

  TIMEELAPSED
  *retvertices = vertices;
  *retgouraudnormals = gouraudnormals;
  *rettriangleindex = triangleindex;
  *retquadindex = quadindex;
  return 0;
}

EDIT: You did mean the lay out right? Not something else?

There you go:


ANSI C syntaxing:

int entity::loadObj(const char *loc,\
                    float **retvertices, float **retgouraudnormals,\
                    int **rettriangleindex, int **retquadindex,\
                    unsigned int *quadcount, unsigned int *trianglecount)
{

    float *vertices, *gouraudnormals;
    int *triangleindex, *quadindex;
    float *normals, *verttext;
    int *trianglenormals, *quadnormals;

    clock_t startTime = clock();
    int fileSize = 0;
    int n, i, j;
    printf("Opening file: \"%s\"\n", loc);

    FILE *pFile = fopen(loc, "r");
    if (pFile == NULL)
    {
        dbgError("fopen()");
        exit(1);
    }

    fseek(pFile, 0, SEEK_END);
    fileSize = ftell(pFile);
    rewind(pFile);

    char *data = (char*) calloc(sizeof(char), fileSize + 20);

    fread(data, 1, fileSize, pFile);
    if (ferror(pFile))
    {
        dbgError("fread()");
        exit(1);
    }
    puts(data);

    fclose(pFile);

    printf("Done reading, parsing file now.\n");
    /*You can return here, the "wrong" data is now written to stdout*/
    return 123;
    /*Or you can continue and let it load all the way*/

    TIMEELAPSED

    printf("Removing #IND if there...");
    char *pIND = data;
    n = 0;
    while (1)
    {
        pIND = strstr(pIND, "#IND");
        if (pIND != NULL)
        {
            memcpy(pIND, "0000", sizeof(char) * 4);
            n++;
        }
        else break;
    }
    printf("Removed %d #INDs\n", n);
    TIMEELAPSED

    printf("Counting lines and determining maximum length...");
    int maxLen, lenCount;
    int lines;

    for (i = lines = lenCount = maxLen = 0; i <= fileSize; i++)
    {
        if (data[i] == '\n')
        {
            lines++;
            lenCount++;
            if (lenCount > maxLen) maxLen = lenCount;
            lenCount = 0;
        }
        lenCount++;
    }

    printf("Counted %d lines, maximum length: %d\n", lines, maxLen);
    TIMEELAPSED

    printf("Allocating %d strings of %d chars...", lines, maxLen);
    char **parsedText = (char**) calloc(sizeof(char*), lines);
    for (n = 0; n < lines; n++)
    {
        parsedText[n] = (char*) malloc(sizeof(char) * maxLen);
        if (parsedText[n] == NULL)
        {
            printf("Malloc failed to allocate %d bytes for parsedText[%d].\n", maxLen, n);
            return -1;
        }
    }
    printf("Done\n");
    TIMEELAPSED

    printf("Reading in 2D array...");
    for (i = n = j = 0; n < lines; i++)
    {
        if (data[i] == '\n')
        {
            parsedText[n][j] = '\0';
            puts(parsedText[n]);

            n++;
            j = 0;
            continue;
        }
        //printf("parsedText[%d][%d] = textTree[%d] = %c\n", n, j, i, data[i]);
        parsedText[n][j] = data[i];
        j++;
    }
    printf("Done\n");
    TIMEELAPSED

    //free the data, we don't need it anymore since it's stored in parsedText
    free(data);


    printf("Counting...");

    int vertlines, normallines, facelines, texturelines;
    vertlines = normallines = facelines = texturelines = 0;

    unsigned int faceverts, maxFaceverts, trianglecnt, quadcnt;
    faceverts = maxFaceverts = trianglecnt = quadcnt = 0;

    //stores for every face line how many verts it has.
    int *facevertcnt = (int*)calloc(sizeof(int), lines);
    for (i = 0; i < lines; i++)
    {
        if (parsedText[i][0] == '#') continue;

        if (parsedText[i][0] == 'v' && parsedText[i][1] == ' ')
        {
            vertlines++;
        }

        else if (parsedText[i][0] == 'v' && parsedText[i][1] == 'n')
        {
            normallines++;
        }

        else if (parsedText[i][0] == 'f' && parsedText[i][1] == ' ')
        {
            facelines++;
            for (n = 2; !isdigit(parsedText[i][n]); n++);
            faceverts = countSpaces(&parsedText[i][n]);
            if (faceverts == 2)
            {
                trianglecnt++;
                //printf("triangle: %s\n", parsedText[i]);
            }
            else if (faceverts == 3)
            {
                quadcnt++;
                //printf("quad: %s", parsedText[i]);
            }
            if (faceverts > maxFaceverts) maxFaceverts = faceverts;
            facevertcnt[i] = faceverts;
            //getchar();
        }

        else if (parsedText[i][0] == 'v' && parsedText[i][1] == 't')
        {
            texturelines++;
        }

        else
        {
            printf("WARNING: Line not supported: %s\n", parsedText[i]);
        }
    }

    int vertvals = vertlines * 3;
    int normalvals = normallines * 3;
    int texturevals = texturelines * 2;
    int triangleverts = trianglecnt * 3;
    int quadverts = quadcnt * 4;

    *trianglecount = trianglecnt;
    *quadcount = quadcnt;

    printf("Counted:\n\t%d vertices\n\t%d normals\n\t%d faces (%d triangles, %d quads)\n", vertlines, normallines, facelines, trianglecnt, quadcnt);
    TIMEELAPSED
    if (maxFaceverts > 4)
    {
        printf("WARNING:\n  Model won't be imported correctly due to polygons with more than 4 vertices.\n");
    }

    printf("Allocating memory for data...");
    vertices = (float*)calloc(sizeof(float), vertvals);
    normals = (float*)calloc(sizeof(float), normalvals);
    verttext = (float*)calloc(sizeof(float), texturevals);
    triangleindex = (int*)calloc(sizeof(int), triangleverts);
    trianglenormals = (int*)calloc(sizeof(int), triangleverts);

    quadindex = (int*)calloc(sizeof(int), quadverts);
    quadnormals = (int*)calloc(sizeof(int), quadverts);

    if (vertices == NULL || normals == NULL || verttext == NULL || triangleindex == NULL || trianglenormals == NULL || quadindex == NULL || quadnormals == NULL)
    {
        printf("Failed to allocate enough memory, exiting...\n");
        return -1;
    }


    int vertcount, normalcount, textcount, tricnt, quacnt;

    printf("Done\n");
    TIMEELAPSED

    printf("Reading in data...");
    for (vertcount = normalcount = textcount = tricnt = quacnt = i = 0; i < lines; i++)
    {
        //comment
        if (parsedText[i][0] == '#') continue;
        if (parsedText[i][0] == ' ') continue;

        //vertex
        if (vertlines)
            if (parsedText[i][0] == 'v' && parsedText[i][1] == ' ')
            {
                sscanf(&parsedText[i][2], "%f%f%f", (vertices+vertcount), (vertices+vertcount+1), (vertices+vertcount+2));
                vertcount += 3;
            }

        //normal
        if (normallines)
            if (parsedText[i][0] == 'v' && parsedText[i][1] == 'n')
            {
                sscanf(&parsedText[i][2], "%f%f%f", (normals+normalcount), (normals+normalcount+1), (normals+normalcount+2));
                normalcount += 3;
            }

        //texture
        if (texturelines)
            if (parsedText[i][0] == 'v' && parsedText[i][1] == 't')
            {
                sscanf(&parsedText[i][2], "%f%f", (verttext+textcount), (verttext+textcount+1));
                textcount += 2;
            }

        //faces
        if (trianglecnt || quadcnt)
            if (parsedText[i][0] == 'f' && parsedText[i][1] == ' ')
            {
                if (facevertcnt[i] == 2)
                {
                    //skip all leading spaces
                    for (n = 2; isspace(parsedText[i][n]); n++);
                    //read in the vertexnr
                    sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt));

                    if (normallines)
                    {
                        //skip 2 slashes
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        //read in the normalnr
                        sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt));
                    }

                    for (;!isspace(parsedText[i][n]); n++);
                    sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+1));
                    n++;

                    if (normallines)
                    {
                        //skip 2 slashes
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        //read in the normalnr
                        sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+1));
                    }

                    for (;!isspace(parsedText[i][n]); n++);
                    sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+2));

                    if (normallines)
                    {
                        //skip 2 slashes
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        //read in the normalnr
                        sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+2));
                    }
                    for (j = 0; j < 3; j++)
                    {
                        //-4 on line 4 becomes 0.
                        if (triangleindex[tricnt+j] < 0)
                        {
                            triangleindex[tricnt+j] = i - triangleindex[tricnt+j];
                        }
                        else
                        {
                            triangleindex[tricnt+j]--;
                            trianglenormals[tricnt+j]--;
                        }
                    }

                    tricnt += 3;
                }
                if (facevertcnt[i] == 3)
                {
                    //skip all leading spaces
                    for (n = 2; isspace(parsedText[i][n]); n++);
                    sscanf(&parsedText[i][n], "%d", (quadindex+quacnt));

                    if (normallines)
                    {
                        //skip 2 slashes
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        //read in the normalnr
                        sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt));
                    }

                    for (;!isspace(parsedText[i][n]); n++);
                    sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+1));
                    n++;

                    if (normallines)
                    {
                        //skip 2 slashes
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        //read in the normalnr
                        sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+1));
                    }

                    for (;!isspace(parsedText[i][n]); n++);
                    sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+2));
                    n++;

                    if (normallines)
                    {
                        //skip 2 slashes
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        //read in the normalnr
                        sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+2));
                    }

                    for (;!isspace(parsedText[i][n]); n++);
                    sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+3));

                    if (normallines)
                    {
                        //skip 2 slashes
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        for (; parsedText[i][n] != '/'; n++);
                        n++;
                        //read in the normalnr
                        sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+3));
                    }
                    for (j = 0; j < 4; j++)
                    {
                        //-4 on line 4 becomes 0.
                        if (quadindex[quacnt+j] < 0)
                        {
                            quadindex[quacnt+j] = i - quadindex[quacnt+j];
                        }
                        quadindex[quacnt+j]--;
                        quadnormals[quacnt+j]--;
                    }

                    quacnt += 4;
                }
            }
    }
    printf("Done\n");
    TIMEELAPSED

    if (normallines)
    {
        printf("Calculating Gouraud normals for each vertex...");
        gouraudnormals = (float*)calloc(sizeof(float), vertvals);
        float normalx, normaly, normalz;
        if (trianglecnt != 0)
        {
            //printf("::DBG:: calcing trianglenormals\n");
            for (i = 0; i < triangleverts; i++)
            {
                //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", triangleindex[i]*3, normalvals, trianglenormals[i]*3);
                normalx = normals[trianglenormals[i]*3];
                normaly = normals[trianglenormals[i]*3+1];
                normalz = normals[trianglenormals[i]*3+2];

                gouraudnormals[triangleindex[i]*3]   += normalx;
                gouraudnormals[triangleindex[i]*3+1] += normaly;
                gouraudnormals[triangleindex[i]*3+2] += normalz;
            }
        }

        if (quadcnt != 0)
        {
            //printf("::DBG:: calcing quadnormals\n");
            for (i = 0; i < quadverts; i++)
            {
                //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", quadindex[i]*3, vertvals, quadnormals[i]*3);
                normalx = normals[quadnormals[i]*3];
                normaly = normals[quadnormals[i]*3+1];
                normalz = normals[quadnormals[i]*3+2];

                gouraudnormals[quadindex[i]*3]   += normalx;
                gouraudnormals[quadindex[i]*3+1] += normaly;
                gouraudnormals[quadindex[i]*3+2] += normalz;
            }
        }
        printf("Done\n");
        TIMEELAPSED

        printf("Normalizing normals...");
        for (i = 0; i < normalvals; i += 3)
        {
            normalx = fabs(gouraudnormals[i]);
            normaly = fabs(gouraudnormals[i+1]);
            normalz = fabs(gouraudnormals[i+2]);

            float max = normalx;
            if (normaly > max) max = normaly;
            if (normalz > max) max = normalz;

            //normalize
            if (max != 0)
            {
                gouraudnormals[i]   /= max;
                gouraudnormals[i+1] /= max;
                gouraudnormals[i+2] /= max;
            }
        }

        printf("Done\n");
        TIMEELAPSED
    }
    else
    {
        printf("No normals detected! This version doesn't calculate normals, too lazy. :(\n");
    }

    /*   for(n = 0; n < vertvals; n += 3){
        printf("v %f %f %f\n", vertices[n], vertices[n+1], vertices[n+2]);
      } */

    /*   for(n = 0; n < normalvals; n += 3){
        printf("vn[%d] %f %f %f\n", n/3, normals[n], normals[n+1], normals[n+2]);
      } */

    /*
      for(n = 0; n < texturevals; n += 2){
        printf("vt %f %f\n", verttext[n], verttext[n+1]);
      } */

    /*
      for(n = 0; n < triangleverts; n += 3){
        printf("triangle: %d %d %d\n\t"
               "Normals: %d %d %d\n",\
               triangleindex[n], triangleindex[n+1], triangleindex[n+2],\
               trianglenormals[n], trianglenormals[n+1], trianglenormals[n+2]);
      } */

    /*   for(n = 0; n < quadverts; n += 4){
        printf("Quad: %d %d %d %d\n\t"
               "Normals: %d %d %d %d\n",\
               quadindex[n], quadindex[n+1], quadindex[n+2], quadindex[n+3],\
               quadnormals[n], quadnormals[n+1], quadnormals[n+2], quadnormals[n+3]);
      } */

    /*   if(normallines)
      for(n = 0; n < vertlines; n++){
        printf("Normals for v[%d]: %f %f %f\n", n, gouraudnormals[n*3], gouraudnormals[n*3+1], gouraudnormals[n*3+2]);
      } */

    printf("File succesfully loaded, returning.\n");

    TIMEELAPSED
    *retvertices = vertices;
    *retgouraudnormals = gouraudnormals;
    *rettriangleindex = triangleindex;
    *retquadindex = quadindex;
    return 0;
}

>>I'm parsing this WaveFront .obj file
WaveFront .obj is NOT a text file so it doesn't contain lines, all it contains is a bunch of binary data. You can't treat binary files as if they are text files.


line 1 thru 3: remove the trailing \ character -- c language does not support line continuation characters. Maybe its just a posting error here???

This is not proper ANSI C

You mean the pseudocode he posted? If not, what parts do you think are not ansi c?

>>int entity::loadObj(const char *loc,\

Ok, I think I get it now -- that line (line #1) is c++, not c.

>>int entity::loadObj(const char *loc,\

Ok, I think I get it now -- that line (line #1) is c++, not c.

Yeap. It will not compile correctly as a function using C.

ooh w00ps. Yeah it was C code used in a C++ program as part of an object. If you remove the entity:: it'll work. I hope. ;)

AncientDragon, I'll open it in binary instead and have a look then, thanks.
Aia: Sorry for missing that, I didn't think you meant the writing-style, but then again I couldn't think of anything not conforming to C.

Okay, first wanted to check if it really was a binary file instead of text file, so just created a big text file and read that in. Same results:

The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
The dog, Ziggi, fetched the paper and drooled all over it.
/*ORIGINAL EOF*/
it.

etched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

The dog, Ziggi, fetched the paper and drooled all over it.

Since the error persists I'm sure it also effects textfiles. I am now thinking of simply memsetting the buffer to zero after filesize bytes. It may be a bad hack, but it should fix this. However, fread seems to be messing up?

Several minutes later:
That hack doesn't seem to work. I have NO clue as of why. The original file has 109368 lines. The output of my program happily continues after that, even with this code:

int fileSize = 0;
    int n, i, j;
    printf("Opening file: \"%s\"\n", loc);

    FILE *pFile = fopen(loc, "r");
    if (pFile == NULL)
    {
        dbgError("fopen()");
        exit(1);
    }

    fseek(pFile, 0, SEEK_END);
    fileSize = ftell(pFile);
    rewind(pFile);

    printf("Allocating %d bytes...\n", fileSize);
    char *data = (char*) calloc(sizeof(char), fileSize + 20);

    fread(data, 1, fileSize, pFile);
    if (ferror(pFile))
    {
        dbgError("fread()");
        exit(1);
    }
    data[fileSize] = '\0';
    puts(data);

    fclose(pFile);

    printf("Done reading, parsing file now.\n");
    /*You can return here, the "wrong" data is now written to stdout*/
    return 123;

Note I am setting the nullbyte in the string. Int filesize matches the filesize Windows (and ConTEXT when editing) reports. Puts seems to be ignoring the null byte, since it will continue to output even after filesize bytes.

Its impossible for anyone to actually test the code you posted, so create a small test program that contains only that function, main(), and any other supporting functions to make it compile and testable. Otherwise we're just sooting in the dark about whats causing the problem.

Yeah sorry, didn't really think about it.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int loadAndOutputFile(char *loc){
    int fileSize = 0;
    printf("Opening file: \"%s\"\n", loc);

    FILE *pFile = fopen(loc, "r");
    if (pFile == NULL)
    {
        perror("fopen()");
        exit(1);
    }

    fseek(pFile, 0, SEEK_END);
    fileSize = ftell(pFile);
    rewind(pFile);

    printf("Allocating %d bytes...\n", fileSize);
    char *data = (char*) calloc(sizeof(char), fileSize*2);

    fread(data, 1, fileSize, pFile);
    if (ferror(pFile))
    {
        perror("fread()");
        exit(1);
    }
    memset(data+fileSize, 0, fileSize);
    int outputBytes = printf("%s", data);
    printf("\nOutput counted %d bytes.", outputBytes);

    fclose(pFile);

    printf("Done reading, parsing file now.\n");
    /*You can return here, the "wrong" data is now written to stdout*/
    return 123;
}

int main(int argc, char **argv){
  loadAndOutputFile(argv[1]);
  return 0;
}

It's best to tunnel the output, it only seems to occur with quite big files, anubis.obj is 458KB.

By the way, on my machine outputBytes is way bigger than fileSize. :(

Come to think of it, the size of the file doesn't matter. digi.obj is way bigger, almost 2MB, and it doesn't have the errors...

I've attached the textfile and the WaveFront .obj file as a zip for you to reproduce the errors I had.

Behold! The error has been found. fread() shall be used on binary opened files only. Thanks go to Prabakar for noticing it. So, WaveFront .obj files are text files, but fread() can't be used to read blocks of data from files opened in textmode.

So, change the above code opening mode to "rb" and it works like a charm. :D

Or maybe it is because fread() convert CRLF to LF, thus fileSize being wrong... Whatever it is, on Windows it's not advisable to use it on text files containing CRLFs I guess.

fread() should only be used when opening the file in binary mode. Doesn't matter if the file was originally written in text mode and contains CRLFs. When opened in binary mode there is no translation to '\n' because they are treated just like any other binary data.

Yeah, but I think the problem is with fileSize being wrong, no? Suppose filesize would exactly the amount of bytes fread would read even in text-mode, like on linux and apple systems... there is no problem in using fread() then, right?

You have reffered me but my post is'nt here. So I will take our chat conversation here. I did say fread can be used only with binary mode, but after browsing msdn, I found that the problem is with ftell() and not fread() as I originally mentioned.

This article has been dead for over six months. Start a new discussion instead.