PDA

View Full Version : parsing .pth with C or VB


paXton
25th March 2006, 14:56
Hi!

I think i need some help for parsing the .pth-files.

I originally want to use them in VB6, but don't know how. So I modified a dirty C source from an earlier project to show the values, which are stored in the pth-files. But then the problems began.


#include "stdafx.h"


#include <cstdlib>

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <ctime>

typedef struct {
int centreX; // fp
int centreY; // fp
int centreZ; // fp
float dirX; // float
float dirY; // float
float dirZ; // float
float limit_left; // outer limit
float limit_right; // outer limit
float drive_left; // road limit
float drive_right; // road limit
} LFSpth_node;


typedef struct {
char LFSPTH[6]; // do not read file if no match
char version; // 0 - do not read file if > 0
char revision; // 0 - do not read file if > 0
int num_nodes; // number
int finish_line; // number
LFSpth_node nodes; // NODE BLOCKS
} LFSpth;



/*
num unit offset description
--- ---- ------ -----------
HEADER BLOCK :
6 char 0 LFSPTH : do not read file if no match
1 byte 6 version : 0 - do not read file if > 0
1 byte 7 revision : 0 - do not read file if > 0
1 int 8 num nodes : number
1 int 12 finish line : number
......NODE BLOCKS

NODE BLOCK :
1 int 0 centre X : fp
1 int 4 centre Y : fp
1 int 8 centre Z : fp
1 float 12 dir X : float
1 float 16 dir Y : float
1 float 20 dir Z : float
1 float 24 limit left : outer limit
1 float 28 limit right : outer limit
1 float 32 drive left : road limit
1 float 36 drive right : road limit
*/




using namespace std;

//Vector, which contains the binary Data of Filename in char order
std::vector <unsigned char> input;


int main( int argc, char ** argv)
{
if (argc != 2) {
std::cerr << "usage: " << argv[0] << " file.pth\n";
exit(1);
}
char *Filename = argv[1];

//Temporary buffer
char buffer;
int buffercnt=0;

//Input Stream
std::ifstream filein;

//open Input stream in binary mode
filein.open(Filename,std::ios::binary);

if (!filein)
{
std::cout << "Error opening the file! Aborting...\n";
exit(1);
}

//Read file and fill buffer until EndOfFile
while (!filein.eof()) {

//read char
filein.get(buffer);
//insert char
input.push_back(buffer);

}
//close file
filein.close();

int offset=16;


char version=input[6];
char revision=input[7];
int num_nodes=input[8];
int finish_line=input[12];

std::string name;


std::cout << "Type:\t\t" << char(input[0]) << char(input[1]) << char(input[2]) << char(input[3]) << char(input[4]) << char(input[5]) << std::endl;
std::cout << "Version:\t" << int(version) << std::endl;
std::cout << "Revision:\t" << int(revision) << std::endl;
std::cout << "Nodes:\t\t" << int(num_nodes) << std::endl;
std::cout << "Finish Line:\t" << int(finish_line) << std::endl << std::endl;


for (int satz = 1; satz <= num_nodes; satz++) {

std::cout << "Node:\t\t\t" << satz << std::endl;

std::cout << "centre X:\t\t" << int(input[offset]) << std::endl;
std::cout << "centre Y:\t\t" << int(input[offset+4]) << std::endl;
std::cout << "centre Z:\t\t" << int(input[offset+8]) << std::endl;


float dirX = input[offset+12] << 24;
dirX += input[offset+13] << 16;
dirX += input[offset+14] << 8;
dirX += input[offset+15] ;

float dirY = input[offset+16];
dirY += input[offset+17] << 8;
dirY += input[offset+18] << 16;
dirY += input[offset+19] << 24;

float dirZ = input[offset+20];
dirZ += input[offset+21] << 8;
dirZ += input[offset+22] << 16;
dirZ += input[offset+23] << 24;

std::cout << "dir X:\t\t\t" << dirX << std::endl;
std::cout << "dir Y:\t\t\t" << dirY << std::endl;
std::cout << "dir Z:\t\t\t" << dirZ << std::endl;

std::cout << "limit left:\t\t" << float(input[offset+24]) << std::endl;
std::cout << "limit right:\t\t" << float(input[offset+28]) << std::endl;

std::cout << "drive left:\t\t" << float(input[offset+32]) << std::endl;
std::cout << "drive right:\t\t" << float(input[offset+36]) << std::endl << std::endl;


offset+=40;
}

return EXIT_SUCCESS;
}

I don't think, the float values are right. But i have no idea how to read them correctly. Is it right, that the "z direction" in BL1.pth is always zero?

I'll be very happy, if someone could show me a hint, how to do it.
Perhaps some code snip sets in VB6 or C.

As you see, I'm not very familiar with C or VB6. Years ago I programmed a lot of command line tools in AmigaE and MaxxonBasic, but now i feel like a noob. 8)

BTW: Many thx @RayOK for his VB6 examples.

Ciao... Pascal

PS: Sorry for my bad english.

Victor
25th March 2006, 15:27
i'm no C expert at all, but is
float dirZ = input[offset+20];
dirZ += input[offset+21] << 8;
dirZ += input[offset+22] << 16;
dirZ += input[offset+23] << 24;
the way to read a float?! Kinda doubt it because the 4 bytes in a float have different meanings than the bytes in an int.

reading a float i have done like :
float File_FloatIn (FILE *fp) {
float Float;
byte *f_ptr = (byte *) &Float;
for (int x=0; x<4; x++) f_ptr[x] = fgetc (fp);

//printf ("READ FLOAT: %f\n", Float);

return Float;
}

that way you put all the 4 bytes of a float directly in an actual float without shifting with bits and all that.

paXton
25th March 2006, 15:52
replace float dirX = ... with int tmpX = ..., then do
float dirX = *(float*)&tmpX;

that's it. thanks :thumb:

But i always get dirZ=0 for every node. Perhaps i should check it with a hex editor.

Stuff
26th March 2006, 00:34
I made an example in VB6 and I also get 0 for every DirZ. Not sure about the path structure but I guess if we both get it, its intended.

Source.. use as you wish :)

paXton
26th March 2006, 08:03
@Victor:Kinda doubt it because the 4 bytes in a float have different meanings than the bytes in an int.

reading a float i have done like :
float File_FloatIn (FILE *fp) {
float Float;
byte *f_ptr = (byte *) &Float;
for (int x=0; x<4; x++) f_ptr[x] = fgetc (fp);

//printf ("READ FLOAT: %f\n", Float);

return Float;
} that way you put all the 4 bytes of a float directly in an actual float without shifting with bits and all that.
jepp, my shifting was totally bullshit. thx


@Stuff:I made an example in VB6 and I also get 0 for every DirZ. Not sure about the path structure but I guess if we both get it, its intended.

Source.. use as you wish :)
:boing:ahhhh...thx. I've also worked on VB6 yesterday and get it working too, but your source looks much nicer and more complete, so I merge it with my next. 8)

Kegetys
26th March 2006, 08:48
I wrote this but never used it for anything so I'm not 100% sure if it is all correct:


#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

// PTH format header
typedef struct {
char LFSPTH[6];
unsigned char version;
unsigned char revision;
int numNodes;
int finishLine;
} PTHHEADER;

// PTH format block
typedef struct {
int cX, cY, cZ; // Centre
float dirX, dirY, dirZ; // Dir
float limitLeft, limitRight;
float driveLeft, driveRight;
} NODEBLOCK;

// PTH file
typedef struct {
PTHHEADER header;
NODEBLOCK *nodes;
bool loaded;
} PTHFILE;

#define fptof(x) (float) x/65536

// Loads a pth file or releases if fname = null
bool loadPTH(PTHFILE* pthf, char *fname) {
// Release memory if loaded
if(pthf->loaded && pthf->nodes != NULL) {
delete[] pthf->nodes;
pthf->nodes = NULL;
pthf->loaded = false;
}

if(!fname)
return false;

// Open file
FILE *f = fopen(fname, "rb");
if(!f)
return false;

// Load header
fread(&pthf->header, sizeof(PTHHEADER), 1, f);
if(strcmp(pthf->header.LFSPTH, "LFSPTH")) {
// Not a pth file? TODO: add more checking here (file size etc.)
fclose(f);
return false;
}

// Allocate memory & load nodes
pthf->nodes = new NODEBLOCK[pthf->header.numNodes];
for(int i=0;i<pthf->header.numNodes;i++)
fread(&pthf->nodes[i], sizeof(NODEBLOCK), 1, f);

pthf->loaded = true;
fclose(f);
return true;
}

void main(void) {
PTHFILE pthf;
pthf.loaded = false;

if(!loadPTH(&pthf, "FE1.pth")) {
printf("Cant load PTH\n");
return;
}

printf("PTH loaded, numnodes: %d, finishline: %d\n", pthf.header.numNodes, pthf.header.finishLine);
for(int i=0;i<pthf.header.numNodes;i++) {
NODEBLOCK* n = &pthf.nodes[i];
printf(" - node %04d: c(%.2f %.2f %.2f) dir(%.2f %.2f %.2f)\n", i, fptof(n->cX), fptof(n->cY), fptof(n->cZ), n->dirX, n->dirY, n->dirZ);
printf(" limit(%.2f %.2f) drive(%.2f %.2f)\n", n->limitLeft, n->limitRight, n->driveLeft, n->driveRight);
}

// Release memory
loadPTH(&pthf, NULL);
}