Notifications
Clear all

[Closed] Reading Krakatoa PRT file?

I’ve been working on a little c++ app that just reads a prt file for now. Will do more once I get that step working. I have been having getting it work, I have found some code on the web but Its just not quite working. Some channels seem to not have enough data and some have incorrect data. If anyone can offer some insight it would be appreciated. Here is my source code, and attached compiled version. Thanks in advance.

targetver.h


#pragma once

// The following macros define the minimum required platform.  The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 
// your application.  The macros work by enabling all features available on platform versions up to and 
// including the version specified.

// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
#endif

PRT.h

#ifndef PRT_H
#define PRT_H

#include <boost/scoped_array.hpp>
#include <boost/shared_array.hpp>
#include <Half.h>
#include <iostream>
#include <zlib.h>
#include <string>
#include <map>

enum DataType
{
		kUNKNOWN,
		kINT16 = 0,
		kINT32 = 1,
		kINT64 = 2,
		kFLOAT16 = 3,
		kFLOAT32 = 4,
        kFLOAT64 = 5,
		kUINT16 = 6,
        kUINT32 = 7,
        kUINT64 = 8,
		kINT8 = 9,
		kUINT8 = 10
};

typedef boost::shared_array<char> Array;

class PRTChannel
{
public:
        PRTChannel() : Arity(0), DT(kUNKNOWN)
		{
        }
        ~PRTChannel()
        {
        }
        int Arity;
        DataType DT;
        Array Data;
};

typedef std::map<std::string, PRTChannel> PRTChannelDict;

class PRT
{
public:
        
        PRT(const long long Count = 0);
        ~PRT();
        
        bool SaveToFile(const char*);
        bool ReadFromFile(const char*);

        void AddChannel(const std::string&, const DataType, const int, const Array&);
        void GetChannels(PRTChannelDict&) const;
        long long GetCount() const;
		int GetDataSize(DataType);
		float GetDataValue(char*, DataType);

        void Clear();

private:
        long long mCount;
        PRTChannelDict mCh;
};

struct Header
{
        char MagicNumber[8];
        int Len;
        char Signature[32];
        int Version;
        long long Count;
};

struct Channel
{
        char Name[32];
        int DataType;
        int Arity;
        int Offset;
};

void PRT::AddChannel(const std::string& Attr, const DataType DT, const int Arity, const Array& Data)
{
        if( Attr == "" || DT == kUNKNOWN || Arity == 0 || Data.get() == NULL )
                return;

        PRTChannel Ch;
        Ch.Arity = Arity;
        Ch.DT = DT;
        Ch.Data = Data;

        mCh.insert( std::make_pair(Attr, Ch) );
}

bool PRT::SaveToFile(const char* Path)
{
        if( mCount == 0 )
                return false;
                
        //Create file to write
        FILE* FP = fopen(Path, "wb");
        if( FP == NULL )
                return false;
        
        //Initialize the header
        Header H;
        memset(&H,0,sizeof(Header));
        H.MagicNumber[0] = 192;
        H.MagicNumber[1] = 'P';
        H.MagicNumber[2] = 'R';
        H.MagicNumber[3] = 'T';
        H.MagicNumber[4] = '\r';
        H.MagicNumber[5] = '
';
        H.MagicNumber[6] = 26;
        H.MagicNumber[7] = '
';
        H.Len = 56;
        sprintf(H.Signature,"Extensible Particle Format");
        H.Version = 1;
        H.Count = mCount;

        fwrite(&H,sizeof(Header),1,FP);
        int RESERVED = 4;
        fwrite(&RESERVED,sizeof(int),1,FP);

        fflush(FP);
        
        try
        {
                //We need double sized memory space.
                size_t TotalSize = 0;
                size_t SingleSize = 0;
                for( std::map<std::string, PRTChannel>::iterator itr = mCh.begin(); itr != mCh.end(); ++itr)
                {
                        const DataType CurrDT = itr->second.DT;
                        const int Arity = itr->second.Arity;

                        if( CurrDT == kINT16 || CurrDT == kFLOAT16 || CurrDT == kUINT16 )
                                SingleSize += 2*Arity;
                        else if( CurrDT == kINT32 || CurrDT == kFLOAT32 || CurrDT == kUINT32 )
                                SingleSize += 4*Arity;
                        else if( CurrDT == kINT64 || CurrDT == kFLOAT64 || CurrDT == kUINT64 )
                                SingleSize += 8*Arity;
						else	
								SingleSize += Arity;
                }
                TotalSize = SingleSize*mCount;

                boost::shared_array<Bytef> Cache( new Bytef[SingleSize] );
                boost::shared_array<Bytef> OutputBuf( new Bytef[TotalSize*2] );

                for( long long i=0; i<mCount; ++i )
                {
                        size_t Offset = 0;
                        for( std::map<std::string, PRTChannel>::iterator itr = mCh.begin(); itr != mCh.end(); ++itr)
                        {
                                const DataType CurrDT = itr->second.DT;
                                const int Arity = itr->second.Arity;
                                const char* p = itr->second.Data.get();
                                size_t Len = 0;

                                if( CurrDT == kINT16 || CurrDT == kFLOAT16 || CurrDT == kUINT16 )
                                        Len = 2*Arity;
                                else if( CurrDT == kINT32 || CurrDT == kFLOAT32 || CurrDT == kUINT32 )
                                        Len = 4*Arity;
                                else if( CurrDT == kINT64 || CurrDT == kFLOAT64 || CurrDT == kUINT64 )
                                        Len = 8*Arity;
                                else
                                        Len = Arity;

                                memcpy( Cache.get() + Offset, p + i*Len, Len );

                                Offset += Len;
                        }

                        memcpy( OutputBuf.get()+i*SingleSize, Cache.get(), SingleSize );
                }
                
                //Compress data
                uLongf ZSrcBufLen = TotalSize;
                Bytef* ZSrcBuf = (Bytef*)OutputBuf.get();

                uLongf ZDstBufLen = ZSrcBufLen;
                Bytef* ZDstBuf = ZSrcBuf + ZSrcBufLen;
        

                int ZR = compress2(ZDstBuf,&ZDstBufLen,ZSrcBuf,ZSrcBufLen,6);
                if( ZR != Z_OK )
                {
                        fclose(FP);
                        remove(Path);
                        return false;
                }

                //Write channels information
                int ChanNumer = mCh.size();
                fwrite(&ChanNumer,sizeof(int),1,FP);
                int ChanLen = 44;
                fwrite(&ChanLen,sizeof(int),1,FP);
                fflush(FP);
                
                int Offset = 0;
                for( std::map<std::string, PRTChannel>::iterator itr = mCh.begin(); itr != mCh.end(); ++itr)
                {
                        Channel Ch;
                        memset(&Ch,0,sizeof(Channel));

                        Ch.Arity = itr->second.Arity;
                        Ch.DataType = (int)itr->second.DT;
                        strncpy(Ch.Name, itr->first.c_str(), 31);
                        Ch.Offset = Offset;

                        const DataType CurrDT = itr->second.DT;
                        if( CurrDT == kINT16 || CurrDT == kFLOAT16 || CurrDT == kUINT16 )
                                Offset += 2*Ch.Arity;
                        else if( CurrDT == kINT32 || CurrDT == kFLOAT32 || CurrDT == kUINT32 )
                                Offset += 4*Ch.Arity;
                        else if( CurrDT == kINT64 || CurrDT == kFLOAT64 || CurrDT == kUINT64 )
                                Offset += 8*Ch.Arity;
                        else
                                Offset += Ch.Arity;

                        fwrite(&Ch,sizeof(Channel),1,FP);
                }

                fwrite(ZDstBuf,ZDstBufLen,1,FP);

                fflush(FP);
                fclose(FP);
        }catch(...)
        {
                fclose(FP);
                remove(Path);
                return false;
        }
        
        return true;
}

bool PRT::ReadFromFile(const char* Path)
{
        FILE* FP = fopen(Path,"rb");
        if( FP == NULL )
        {
			std::cerr<<"e@fopen"<<std::endl;
                return false;
        }

        Header H;
        memset(&H,0,sizeof(Header));

        fread(&H,sizeof(Header),1,FP);

        if( strncmp(H.Signature,"Extensible Particle Format",31) != 0 )
                return false;

        if( H.Len != 56  )
                return false;

        if( H.Version != 1 )
                return false;

        int REVERSED = 0;
        fread(&REVERSED,sizeof(int),1,FP);

        if( REVERSED != 4 ) 
                return false;

        int ChDef[2] = {0,0};
        fread(&ChDef[0],sizeof(int)*2,1,FP);
        if( ChDef[0] == 0 || ChDef[1] != 44 )
                return false;

        const int ChCount = ChDef[0];

        try
        {
                boost::scoped_array<Channel> Channels(new Channel[ChCount]);
                memset(Channels.get(),0,sizeof(Channel)*ChCount);
                fread(Channels.get(),sizeof(Channel),ChCount,FP);

                size_t SingleSize = 0;
                for( int i=0; i<ChDef[0]; ++i )
                {
                        DataType CurrDT = (DataType)Channels[i].DataType;
						if( CurrDT == kINT16 || CurrDT == kFLOAT16 || CurrDT == kUINT16 )
                        {
                                PRTChannel Ch;
                                Ch.Arity = Channels[i].Arity;
                                Ch.Data.reset(new char[H.Count*2*Ch.Arity]);
                                Ch.DT = CurrDT;
								mCh.insert( std::make_pair(Channels[i].Name,Ch) );
                                SingleSize += 2*Ch.Arity;
                        }
                        else if( CurrDT == kINT32 || CurrDT == kFLOAT32 || CurrDT == kUINT32 )
                        {
                                PRTChannel Ch;
                                Ch.Arity = Channels[i].Arity;
                                Ch.Data.reset(new char[H.Count*4*Ch.Arity]);
                                Ch.DT = CurrDT;
								mCh.insert( std::make_pair(Channels[i].Name,Ch) );
                                SingleSize += 4*Ch.Arity;
                        }
                        else if( CurrDT == kINT64 || CurrDT == kFLOAT64 || CurrDT == kUINT64 )
                        {
                                PRTChannel Ch;
                                Ch.Arity = Channels[i].Arity;
                                Ch.Data.reset(new char[H.Count*8*Ch.Arity]);
                                Ch.DT = CurrDT;
								mCh.insert( std::make_pair(Channels[i].Name,Ch) );
                                SingleSize += 8*Ch.Arity;
                        }
                        else
                        {
                                PRTChannel Ch;
                                Ch.Arity = Channels[i].Arity;
                                Ch.Data.reset(new char[H.Count*Ch.Arity]);
                                Ch.DT = CurrDT;
								mCh.insert( std::make_pair(Channels[i].Name,Ch) );

                                SingleSize += Ch.Arity;
                        }
                }

                if( SingleSize == 0 )
                        return false;

                
                long CurrFilePos = ftell(FP);
                fseek(FP,0,SEEK_END);
                unsigned long ZSrcLen = ftell(FP) - CurrFilePos;
                fseek(FP,CurrFilePos,SEEK_SET);

                boost::scoped_array<Bytef> ZSrc(new Bytef[ZSrcLen]);
                fread(ZSrc.get(),ZSrcLen,1,FP);

                uLongf ZDstLen = SingleSize*H.Count;
                boost::scoped_array<Bytef> ZDst(new Bytef[ZDstLen]);

                int ZE = uncompress(ZDst.get(),&ZDstLen,ZSrc.get(),ZSrcLen);

                if( ZE != Z_OK )
                        return false;

                int AccOffset = 0;
                int mChIdx = 0;
                char* WholePointer = (char*)ZDst.get();
				for( PRTChannelDict::iterator itr = mCh.begin(); itr != mCh.end(); ++itr )
                {
                        DataType CurrDT = (DataType)itr->second.DT;
                                                
                        int Size = 0;

                        if( CurrDT == kINT16 || CurrDT == kFLOAT16 || CurrDT == kUINT16 )
                                Size = 2*itr->second.Arity;
                        else if( CurrDT == kINT32 || CurrDT == kFLOAT32 || CurrDT == kUINT32 )
                                Size = 4*itr->second.Arity;
                        else if( CurrDT == kINT64 || CurrDT == kFLOAT64 || CurrDT == kUINT64 )
                                Size = 8*itr->second.Arity;
                        else
                                Size = itr->second.Arity;

                        AccOffset += mChIdx*Size;

                        char* RawPointer = itr->second.Data.get();
                        for( long long int n=0; n<H.Count; ++n )
                        {
                                memcpy( RawPointer+n*Size, WholePointer+SingleSize*n+AccOffset, Size );
                        }

                        ++mChIdx;
                }

                mCount = H.Count;
        }
        catch(...)
        {
                return false;
        }
        return true;
}



void PRT::Clear()
{
        mCount = 0;
        mCh.clear();
}

void PRT::GetChannels(PRTChannelDict& Dict) const
{
        Dict = mCh;
}

long long PRT::GetCount() const
{
        return mCount;
}

int PRT::GetDataSize(DataType CurrDT)
{
	int DataSize = 0;

	if( CurrDT == kINT16 || CurrDT == kFLOAT16 || CurrDT == kUINT16 )
		DataSize = 2;
	else if( CurrDT == kINT32 || CurrDT == kFLOAT32 || CurrDT == kUINT32 )
		DataSize = 4;
	else if( CurrDT == kINT64 || CurrDT == kFLOAT64 || CurrDT == kUINT64 )
		DataSize = 8;
	else
		DataSize = 1;

	return DataSize;
}

float PRT::GetDataValue(char* data, DataType type)
{
	float out = 0;
	
	switch(type)
	{
	case kINT16:
		out = (float)(__int16)*data;
		break;
	case kINT32:
		out = reinterpret_cast<__int32&>(*data);;
		break;
	case kINT64:
		out = (float)(__int64)*data;
		break;
	case kFLOAT16:
		//out = (float)h;
		break;
	case kFLOAT32:
		out = reinterpret_cast<float&>(*data);
		break;
	case kFLOAT64:
		out = (float)(double)*data;
		break;
	case kUINT16:
		break;
	case kUINT32:
		break;
	case kUINT64:
		break;
	case kINT8:
		break;
	case kUINT8:
		break;
	}

	return out;
}

PRT::PRT(const long long Count) : mCount(Count)
{
}

PRT::~PRT()
{
}

#endif

prtreader.cpp

#include "targetver.h"
#include <stdio.h>
#include <tchar.h>

#include "PRT.h"


int main(int argc, const char* argv[])
{
	PRT prt;
	bool prt_ok = prt.ReadFromFile(argv[1]);
	if(!prt_ok){
		std::cerr << "e@prt.ReadFromFile";
		return 1;
	}

	__int64 pcount = prt.GetCount();

	PRTChannelDict channels;
	prt.GetChannels(channels);
	
	for(PRTChannelDict::iterator itr = channels.begin(); itr != channels.end(); ++itr){
		std::string name = itr->first;
		PRTChannel channel = itr->second;
		
		DataType CurrDT = itr->second.DT;
        int Arity = itr->second.Arity;
		int DataSize = prt.GetDataSize(CurrDT);

		std::cout << name << std::endl;
		std::cout << Arity << std::endl;
		std::cout << DataSize << std::endl;

		char* data = channel.Data.get();
		
		__int64 index = 0;
		char* buffer = new char[DataSize];
		for(__int64 i = 0; i < pcount*Arity; ++i){
			for(int n = 0; n < DataSize; ++n){
				buffer[n] = data[index];
				++index;
			}
			
			float value = prt.GetDataValue(buffer, CurrDT);
			std::cout << value << " ";
		}
		std::cout << std::endl;
		delete buffer;
	}

	return 0;
}
2 Replies
 lo1

I haven’t gone over your code but this webpage describes the prt format:
http://www.thinkboxsoftware.com/krak-prt-file-format/

Thanks I’ve seen that and have followed it to the letter, but still doesn’t seem to work. Thanks for the link.