/* ************************ Copyright Terrain Experts Inc. Terrain Experts Inc (TERREX) reserves all rights to this source code unless otherwise specified in writing by the President of TERREX. This copyright may be updated in the future, in which case that version supercedes this one. ------------------- Terrex Experts Inc. 4400 East Broadway #314 Tucson, AZ 85711 info@terrex.com Tel: (520) 323-7990 ************************ */ #include #include #include #include /* trpage_readbuf.cpp Methods for the trpgReadBuffer and trpgMemReadBuffer classes. trpgReadBuffer is a virtual base class with a few utility functions. It's used as generic interface for reading data out of. trpgMemReadBuffer is a subclass of that which implements methods for reading out of a chunk of memory. Data is read off of disk and then dumped into a read buffer for parsing. If you wanted to read directly from disk, for example, you could implement a trpgDiskReadBuffer as a subclass of trpgReadBuffer. */ #include #include /* ********************** Read buffer base class functions ********************** */ // Basic get functions bool trpgReadBuffer::Get(int32 &ret) { int32 val; if (!GetData((char *)&val,sizeof(int32))) return false; if (ness != cpuNess) ret = trpg_byteswap_int(val); else ret = val; return true; } bool trpgReadBuffer::Get(int64 &ret) { int64 val; if (!GetData((char *)&val,sizeof(int64))) return false; // trpg_byteswap_llong is defined to be 64 bit if (ness != cpuNess) ret = trpg_byteswap_llong(val); else ret = val; return true; } bool trpgReadBuffer::Get(char *ret,int retLen) { int32 len; // Get the length first if (!Get(len)) return false; // Read what we can int rlen = MIN(len,retLen-1); if (!GetData(ret,rlen)) return false; ret[rlen] = 0; // Skip the rest if (!Skip(len-rlen)) return false; return true; } bool trpgReadBuffer::Get(std::string &str) { int32 len; // Get the length first if (!Get(len)) return false; if (len < 0) return false; // Note: Should fix this char *tmpStr = new char[len+1]; // Read it if (!GetData(tmpStr,len)) return false; tmpStr[len] = 0; str = tmpStr; return true; } bool trpgReadBuffer::Get(float32 &ret) { char cval[4]; if (!GetData(cval,sizeof(float32))) return false; try { if (ness == cpuNess) memcpy(&ret,cval,4); else ret = trpg_byteswap_4bytes_to_float(cval); } catch (...) { } return true; } bool trpgReadBuffer::Get(float64 &ret) { char cval[8]; if (!GetData(cval,sizeof(float64))) return false; try { if (ness == cpuNess) memcpy(&ret,cval,8); else ret = trpg_byteswap_8bytes_to_double(cval); } catch (...) { } return true; } bool trpgReadBuffer::Get(uint8 &ret) { uint8 val; if (!GetData((char *)&val,sizeof(uint8))) return false; // No byte swapping needed ret = val; return true; } //#if (bool != int32) bool trpgReadBuffer::Get(bool &ret) { uint8 val; if (!GetData((char *)&val,sizeof(uint8))) return false; // No byte swapping needed ret = (val == 0) ? false : true; return true; } //#endif #if (trpgDiskRef != int64) bool trpgReadBuffer::Get(trpgDiskRef &ret) { trpgDiskRef val; if (!GetData((char *)&val,sizeof(trpgDiskRef))) return false; if (ness == cpuNess) ret = val; else ret = trpg_byteswap_llong(val); return true; } #endif bool trpgReadBuffer::Get(trpgToken &ret) { trpgToken val; if (!GetData((char *)&val,sizeof(trpgToken))) return false; if (ness == cpuNess) ret = val; else ret = trpg_byteswap_short(val); return true; } // Array Get functions bool trpgReadBuffer::GetArray(int len,float32 **arr) { if (!GetDataRef((char **)arr,sizeof(float32)*len)) return false; // Byteswap in place if necessary if (ness != cpuNess) { char *ptr; int pos; for (pos=0,ptr = (char *)*arr;pos 0) limits.resize(len-1); } // Skip To Limit // Skip to the end of the current limit. // This happens when we bag the rest of the current token bool trpgReadBuffer::SkipToLimit() { int len=0; if (limits.size() != 0) len = limits[limits.size()-1]; if (len > 0) return Skip(len); return true; } // Test Limit // See if the next read is going to blow the limits bool trpgReadBuffer::TestLimit(int len) { for (unsigned int i=0;i limits[i]) return false; return true; } // Update Limits // We just read a few bytes. Update the limits void trpgReadBuffer::UpdateLimits(int len) { for (unsigned int i=0;i= len) return true; // Also test the limits for (unsigned int i=0;i totLen) { if (data) delete [] data; data = new char[newLen]; totLen = newLen; } len = newLen; pos = 0; } // Get Data Ptr // Return a pointer to our data so it can be written to char *trpgMemReadBuffer::GetDataPtr() { return data; } // Get Data // Protected method for actually retrieving a piece of data bool trpgMemReadBuffer::GetData(char *ret,int rlen) { if (rlen < 0) return false; // Test against limits imposed from without if (!TestLimit(rlen)) throw 1; // See if we've actually got the data if (pos+rlen > len) throw 1; // Copy into the return buffer memcpy(ret,&data[pos],rlen); // Update any limits we might have UpdateLimits(rlen); pos += rlen; return true; } // Get Reference to Data // Protected method that retrieves a reference to the given amoutn of data bool trpgMemReadBuffer::GetDataRef(char **ret,int rlen) { if (rlen < 0) return false; // Test against limits if (!TestLimit(rlen)) throw 1; if (pos + rlen > len) throw 1; // Set up reference *ret = &data[pos]; UpdateLimits(rlen); pos += rlen; return true; } // Skip // Same as read except we're not, uh, reading bool trpgMemReadBuffer::Skip(int rlen) { if (rlen == 0) return true; if (rlen < 0) return false; // Test against limits if (!TestLimit(rlen)) return false; if (pos + rlen > len) return false; UpdateLimits(rlen); pos += rlen; return true; } /* Appendable File read class */ trpgrAppFile::trpgrAppFile(trpgEndian inNess,const char *fileName) { Init(inNess,fileName); } void trpgrAppFile::Init(trpgEndian inNess,const char *fileName) { valid = false; ness = inNess; cpuNess = trpg_cpu_byte_order(); if (!(fp = fopen(fileName,"rb"))) return; valid = true; } trpgrAppFile::~trpgrAppFile() { if (fp) fclose(fp); valid = false; } bool trpgrAppFile::isValid(void) const { return valid; } // Read a section of data from the given file // and dump it into the given buffer bool trpgrAppFile::Read(trpgMemReadBuffer *buf,int32 offset) { if (!valid) return false; // Seek to the right location if (fseek(fp,offset,SEEK_SET)) return false; // Read a length int32 len; if (fread(&len,sizeof(int32),1,fp) != 1) { valid = false; return false; } // Byteswap if necessary if (ness != cpuNess) len = trpg_byteswap_int(len); if (len < 0) { valid = false; return false; } buf->SetLength(len); char *data = buf->GetDataPtr(); if (!data) { valid = false; return false; } if (fread(data,sizeof(char),len,fp) != (uint32)len) { valid = false; return false; } return true; } /* Read a section of data from the given file and dump it into the given memory. Sanity check the length against the size of the memory passed into dataSize. */ bool trpgrAppFile::Read(char *data,int32 baseOffset,int32 objOffset,int32 dataSize) { if (!valid) return false; // Seek to the right place int result; if ((result = fseek(fp,baseOffset,SEEK_SET))) { valid = false; return false; } // Read the total object length int32 len; if (fread(&len,sizeof(int32),1,fp) != 1) { valid = false; return false; } // Byteswap if necessary if (ness != cpuNess) len = trpg_byteswap_int(len); if (len < 0) { valid = false; return false; } // It's all right to read less than the whole data block if (objOffset+dataSize > len) return false; // Skip to the object offset if (fseek(fp,objOffset,SEEK_CUR)) { valid = false; return false; } // Read the raw data // Note: What about byte swapping? if (fread(data,sizeof(char),dataSize,fp) != (uint32)dataSize) { valid = false; return false; } return true; } /* App File Cache This class manages a group of appendable files with the same base name and extension. It will keep a certain number of them open to facilitate caching. */ trpgrAppFileCache::trpgrAppFileCache(const char *inPre,const char *inExt,int noFiles) { Init(inPre,inExt,noFiles); } void trpgrAppFileCache::Init(const char *inPre,const char *inExt,int noFiles) { strcpy(baseName,inPre); strcpy(ext,inExt); files.resize(noFiles); timeCount = 0; } trpgrAppFileCache::~trpgrAppFileCache() { unsigned int len = files.size(); for (unsigned int i=0;iisValid()) { of.lastUsed = timeCount; return of.afile; } else { if (of.afile) delete of.afile; of.afile = NULL; } } // Didn't find it. Need to reclaim one // Look for the oldest used int oldTime=-1,oldID=-1; for (i=0;i 0) { if(baseName[len]==PATHSEPERATOR[0]) { strcpy(filebase,&baseName[len+1]); strcpy(dir,baseName); dir[len]='\0'; break; } } sprintf(fileName,"%s" PATHSEPERATOR "%d" PATHSEPERATOR "%d" PATHSEPERATOR "%s_%d.%s", dir,col,row,filebase,id,ext); } of.afile = GetNewRAppFile(ness,fileName); of.id = id; of.row = row; of.col = col; of.lastUsed = timeCount; timeCount++; return of.afile; } // Constructor for OpenFile class trpgrAppFileCache::OpenFile::OpenFile() { afile = NULL; lastUsed = 0; id = -1; }