root/OpenSceneGraph/trunk/src/osgPlugins/txp/trpage_readbuf.cpp @ 13041

Revision 13041, 15.2 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* ************************
2   Copyright Terrain Experts Inc.
3   Terrain Experts Inc (TERREX) reserves all rights to this source code
4   unless otherwise specified in writing by the President of TERREX.
5   This copyright may be updated in the future, in which case that version
6   supercedes this one.
7   -------------------
8   Terrex Experts Inc.
9   4400 East Broadway #314
10   Tucson, AZ  85711
11   info@terrex.com
12   Tel: (520) 323-7990
13   ************************
14   */
15
16#include <osgDB/FileUtils>
17
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include <math.h>
22
23/* trpage_readbuf.cpp
24    Methods for the trpgReadBuffer and trpgMemReadBuffer classes.
25    trpgReadBuffer is a virtual base class with a few utility functions.
26    It's used as generic interface for reading data out of.
27    trpgMemReadBuffer is a subclass of that which implements methods for
28     reading out of a chunk of memory.  Data is read off of disk and then
29     dumped into a read buffer for parsing.
30    If you wanted to read directly from disk, for example, you could
31     implement a trpgDiskReadBuffer as a subclass of trpgReadBuffer.
32*/
33
34#include <trpage_io.h>
35#include <trpage_swap.h>
36
37/* **********************
38   Read buffer base class functions
39   **********************
40   */
41
42// Basic get functions
43bool trpgReadBuffer::Get(int32 &ret)
44{
45    int32 val;
46
47    if (!GetData((char *)&val,sizeof(int32)))  return false;
48    if (ness != cpuNess)
49        ret = trpg_byteswap_int(val);
50    else
51        ret = val;
52
53    return true;
54}
55bool trpgReadBuffer::Get(int64 &ret)
56{
57    int64 val;
58
59    if (!GetData((char *)&val,sizeof(int64)))  return false;
60        // trpg_byteswap_llong is defined to be 64 bit
61    if (ness != cpuNess)
62        ret = trpg_byteswap_llong(val);
63    else
64        ret = val;
65
66    return true;
67}
68bool trpgReadBuffer::Get(char *ret,int retLen)
69{
70    int32 len;
71
72    // Get the length first
73    if (!Get(len))  return false;
74
75    // Read what we can
76    int rlen = MIN(len,retLen-1);
77    if (!GetData(ret,rlen))  return false;
78    ret[rlen] = 0;
79
80    // Skip the rest
81    if (!Skip(len-rlen)) return false;
82
83    return true;
84}
85bool trpgReadBuffer::Get(std::string &str)
86{
87    int32 len;
88
89    // Get the length first
90    if (!Get(len)) return false;
91
92    if (len < 0)
93        return false;
94    // Note: Should fix this
95    char *tmpStr = new char[len+1];
96
97    // Read it
98    if (!GetData(tmpStr,len))  return false;
99    tmpStr[len] = 0;
100
101    str = tmpStr;
102
103    return true;
104}
105bool trpgReadBuffer::Get(float32 &ret)
106{
107    char cval[4];
108
109    if (!GetData(cval,sizeof(float32)))  return false;
110    try {
111        if (ness == cpuNess)
112            memcpy(&ret,cval,4);
113        else
114            ret = trpg_byteswap_4bytes_to_float(cval);
115    }
116    catch (...) {
117    }
118
119    return true;
120}
121bool trpgReadBuffer::Get(float64 &ret)
122{
123    char cval[8];
124
125    if (!GetData(cval,sizeof(float64)))  return false;
126    try {
127        if (ness == cpuNess)
128            memcpy(&ret,cval,8);
129        else
130            ret = trpg_byteswap_8bytes_to_double(cval);
131    }
132    catch (...) {
133    }
134
135    return true;
136}
137bool trpgReadBuffer::Get(uint8 &ret)
138{
139    uint8 val;
140
141    if (!GetData((char *)&val,sizeof(uint8)))  return false;
142    // No byte swapping needed
143    ret = val;
144
145    return true;
146}
147
148//#if (bool != int32)
149bool trpgReadBuffer::Get(bool &ret)
150{
151    uint8 val;
152
153    if (!GetData((char *)&val,sizeof(uint8)))  return false;
154    // No byte swapping needed
155    ret = (val == 0) ? false : true;
156
157    return true;
158}
159//#endif
160
161#if (trpgDiskRef != int64)
162bool trpgReadBuffer::Get(trpgDiskRef &ret)
163{
164    trpgDiskRef val;
165
166    if (!GetData((char *)&val,sizeof(trpgDiskRef)))  return false;
167    if (ness == cpuNess)
168        ret = val;
169    else
170        ret = trpg_byteswap_llong(val);
171
172    return true;
173}
174#endif
175
176bool trpgReadBuffer::Get(trpgToken &ret)
177{
178    trpgToken val;
179
180    if (!GetData((char *)&val,sizeof(trpgToken)))  return false;
181    if (ness == cpuNess)
182        ret = val;
183    else
184        ret = trpg_byteswap_short(val);
185
186    return true;
187}
188
189// Array Get functions
190bool trpgReadBuffer::GetArray(int len,float32 **arr)
191{
192    if (!GetDataRef((char **)arr,sizeof(float32)*len))
193        return false;
194    // Byteswap in place if necessary
195    if (ness != cpuNess) {
196        char *ptr;
197        int pos;
198        for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=4)
199            trpg_swap_four(ptr,ptr);
200    }
201
202    return true;
203}
204bool trpgReadBuffer::GetArray(int len,float64 **arr)
205{
206    if (!GetDataRef((char **)arr,sizeof(float64)*len))
207        return false;
208    // Byteswap in place if necessary
209    if (ness != cpuNess) {
210        char *ptr;
211        int pos;
212        for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=8)
213            trpg_swap_eight(ptr,ptr);
214    }
215    return true;
216}
217bool trpgReadBuffer::GetArray(int len,int32 **arr)
218{
219    if (!GetDataRef((char **)arr,sizeof(int32)*len))
220        return false;
221    // Byteswap in place if necessary
222    if (ness != cpuNess) {
223        char *ptr;
224        int pos;
225        for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=4)
226            trpg_swap_four(ptr,ptr);
227    }
228    return true;
229}
230bool trpgReadBuffer::GetArray(int len,trpgColor **arr)
231{
232    if (!GetDataRef((char **)arr,sizeof(trpgColor)*len))
233        return false;
234    // Byteswap in place if necessary
235    if (ness != cpuNess) {
236        char *ptr;
237        int pos;
238        for (pos=0,ptr = (char *)*arr;pos<len;pos++,ptr+=8)
239            trpg_swap_four(ptr,ptr);
240    }
241    return true;
242}
243bool trpgReadBuffer::GetArray(int len,char **arr)
244{
245    return GetDataRef((char **)arr,sizeof(char)*len);
246}
247
248// Utility Get functions - Just call the others
249bool trpgReadBuffer::Get(trpg2iPoint &pt)
250{
251    if (!Get(pt.x) || !Get(pt.y))
252        return false;
253    return true;
254}
255bool trpgReadBuffer::Get(trpg2dPoint &pt)
256{
257    if (!Get(pt.x) || !Get(pt.y))
258        return false;
259    return true;
260}
261bool trpgReadBuffer::Get(trpg3dPoint &pt)
262{
263    if (!Get(pt.x) || !Get(pt.y) || !Get(pt.z))
264        return false;
265    return true;
266}
267bool trpgReadBuffer::Get(trpgColor &color)
268{
269    if (!Get(color.red) || !Get(color.green) || !Get(color.blue))
270        return false;
271    return true;
272}
273
274// Get both a token and it's length, since that's fairly common
275bool trpgReadBuffer::GetToken(trpgToken &tok,int32 &len)
276{
277    if (!Get(tok) || !Get(len))
278        return false;
279
280    return true;
281}
282
283/* Limit Handling functions
284   These impose arbitrary lenght limits on the read buffer.
285   This keeps us from reading pased a token group and parsing
286   random data within an archive.
287*/
288// Push Limit
289// Add another limit to the top of the stack
290void trpgReadBuffer::PushLimit(int limit)
291{
292    limits.push_back(limit);
293}
294
295// Pop Limit
296// Remove the current limit from the stack
297void trpgReadBuffer::PopLimit()
298{
299    int len = limits.size();
300
301    if (len > 0)
302        limits.resize(len-1);
303}
304
305// Skip To Limit
306// Skip to the end of the current limit.
307// This happens when we bag the rest of the current token
308bool trpgReadBuffer::SkipToLimit()
309{
310    int len=0;
311
312    if (limits.size() != 0)
313        len = limits[limits.size()-1];
314
315    if (len > 0)
316        return Skip(len);
317
318    return true;
319}
320
321// Test Limit
322// See if the next read is going to blow the limits
323bool trpgReadBuffer::TestLimit(int len)
324{
325    for (unsigned int i=0;i<limits.size();i++)
326        if (len > limits[i])
327            return false;
328
329    return true;
330}
331
332// Update Limits
333// We just read a few bytes.  Update the limits
334void trpgReadBuffer::UpdateLimits(int len)
335{
336    for (unsigned int i=0;i<limits.size();i++)
337        limits[i] -= len;
338}
339
340/* *************************
341   Memory Read Buffer
342   *************************
343   */
344trpgMemReadBuffer::trpgMemReadBuffer(trpgEndian in_ness)
345{
346    data = NULL;
347    len = totLen = pos = 0;
348    ness = in_ness;
349    cpuNess = trpg_cpu_byte_order();
350}
351trpgMemReadBuffer::~trpgMemReadBuffer()
352{
353    if (data)
354        delete [] data;
355}
356
357// Empty check
358bool trpgMemReadBuffer::isEmpty()
359{
360    if (!data)  return true;
361
362    if (pos >= len)
363        return true;
364
365    // Also test the limits
366    for (unsigned int i=0;i<limits.size();i++)
367        if (limits[i] == 0)  return true;
368
369    return false;
370}
371
372// Set Length
373// Allocate the given space
374void trpgMemReadBuffer::SetLength(int newLen)
375{
376    if (newLen > totLen) {
377        if (data)
378            delete [] data;
379        data = new char[newLen];
380        totLen = newLen;
381    }
382    len = newLen;
383    pos = 0;
384}
385
386// Get Data Ptr
387// Return a pointer to our data so it can be written to
388char *trpgMemReadBuffer::GetDataPtr()
389{
390    return data;
391}
392
393// Get Data
394// Protected method for actually retrieving a piece of data
395bool trpgMemReadBuffer::GetData(char *ret,int rlen)
396{
397    if (rlen < 0)
398        return false;
399
400    // Test against limits imposed from without
401    if (!TestLimit(rlen))  throw 1;
402
403    // See if we've actually got the data
404    if (pos+rlen > len)  throw 1;
405
406    // Copy into the return buffer
407    memcpy(ret,&data[pos],rlen);
408
409    // Update any limits we might have
410    UpdateLimits(rlen);
411
412    pos += rlen;
413
414    return true;
415}
416
417// Get Reference to Data
418// Protected method that retrieves a reference to the given amoutn of data
419bool trpgMemReadBuffer::GetDataRef(char **ret,int rlen)
420{
421    if (rlen < 0)  return false;
422
423    // Test against limits
424    if (!TestLimit(rlen)) throw 1;
425    if (pos + rlen > len)  throw 1;
426
427    // Set up reference
428    *ret = &data[pos];
429
430    UpdateLimits(rlen);
431    pos += rlen;
432
433    return true;
434}
435
436// Skip
437// Same as read except we're not, uh, reading
438bool trpgMemReadBuffer::Skip(int rlen)
439{
440    if (rlen == 0)
441        return true;
442
443    if (rlen < 0)
444        return false;
445
446    // Test against limits
447    if (!TestLimit(rlen))  return false;
448    if (pos + rlen > len)  return false;
449
450    UpdateLimits(rlen);
451
452    pos += rlen;
453
454    return true;
455}
456
457/* Appendable File read class
458 */
459
460trpgrAppFile::trpgrAppFile(trpgEndian inNess,const char *fileName)
461{
462    Init(inNess,fileName);
463}
464
465void trpgrAppFile::Init(trpgEndian inNess,const char *fileName)
466{
467    valid = false;
468    ness = inNess;
469    cpuNess = trpg_cpu_byte_order();
470
471    if (!(fp = osgDB::fopen(fileName,"rb")))
472        return;
473
474    valid = true;
475}
476
477trpgrAppFile::~trpgrAppFile()
478{
479    if (fp)
480        fclose(fp);
481
482    valid = false;
483}
484
485bool trpgrAppFile::isValid(void) const
486{
487    return valid;
488}
489
490// Read a section of data from the given file
491//  and dump it into the given buffer
492bool trpgrAppFile::Read(trpgMemReadBuffer *buf,int32 offset)
493{
494    if (!valid)  return false;
495
496    // Seek to the right location
497    if (fseek(fp,offset,SEEK_SET))
498        return false;
499
500    // Read a length
501    int32 len;
502    if (fread(&len,sizeof(int32),1,fp) != 1) {
503        valid = false;
504        return false;
505    }
506
507    // Byteswap if necessary
508    if (ness != cpuNess)
509        len = trpg_byteswap_int(len);
510
511    if (len < 0) {
512        valid = false;
513        return false;
514    }
515
516    buf->SetLength(len);
517    char *data = buf->GetDataPtr();
518    if (!data) {
519        valid = false;
520        return false;
521    }
522
523        if (fread(data,sizeof(char),len,fp) != (uint32)len) {
524        valid = false;
525        return false;
526    }
527
528    return true;
529}
530
531/* Read a section of data from the given file
532   and dump it into the given memory.  Sanity
533   check the length against the size of the memory
534   passed into dataSize.
535*/
536bool trpgrAppFile::Read(char *data,int32 baseOffset,int32 objOffset,int32 dataSize)
537{
538    if (!valid)  return false;
539
540    // Seek to the right place
541    int result;
542    if ((result = fseek(fp,baseOffset,SEEK_SET))) {
543        valid = false;
544        return false;
545    }
546
547    // Read the total object length
548    int32 len;
549    if (fread(&len,sizeof(int32),1,fp) != 1) {
550        valid = false;
551        return false;
552    }
553
554    // Byteswap if necessary
555    if (ness != cpuNess)
556        len = trpg_byteswap_int(len);
557
558    if (len < 0) {
559        valid = false;
560        return false;
561    }
562
563    // It's all right to read less than the whole data block
564    if (objOffset+dataSize > len)
565        return false;
566
567    // Skip to the object offset
568    if (fseek(fp,objOffset,SEEK_CUR)) {
569        valid = false;
570        return false;
571    }
572
573    // Read the raw data
574    // Note: What about byte swapping?
575    if (fread(data,sizeof(char),dataSize,fp) != (uint32)dataSize) {
576        valid = false;
577        return false;
578    }
579
580    return true;
581}
582
583/* App File Cache
584   This class manages a group of appendable files with
585   the same base name and extension.  It will keep a certain
586   number of them open to facilitate caching.
587*/
588
589trpgrAppFileCache::trpgrAppFileCache(const char *inPre,const char *inExt,int noFiles)
590{
591    Init(inPre,inExt,noFiles);
592}
593
594void trpgrAppFileCache::Init(const char *inPre,const char *inExt,int noFiles)
595{
596    strcpy(baseName,inPre);
597    strcpy(ext,inExt);
598
599    files.resize(noFiles);
600    timeCount = 0;
601}
602
603trpgrAppFileCache::~trpgrAppFileCache()
604{
605    unsigned int len = files.size();
606    for (unsigned int i=0;i<len;i++) {
607        if (files[i].afile) {
608            delete files[i].afile;
609            files[i].afile = NULL;
610        }
611    }
612}
613
614trpgrAppFile *trpgrAppFileCache::GetNewRAppFile(trpgEndian ness, const char *fileName)
615{
616    return new trpgrAppFile(ness,fileName);
617}
618
619trpgrAppFile *trpgrAppFileCache::GetFile(trpgEndian ness,int id)
620{
621    return GetFile(ness,id,-1,-1);
622}
623
624/*
625 */
626trpgrAppFile *trpgrAppFileCache::GetFile(trpgEndian ness,int id,int col,int row)
627{
628    // Look for it already here
629    int foundID = -1;
630    unsigned int i;
631    for (i=0;i<files.size();i++) {
632        if ((files[i].id == id)&&
633            (files[i].col == col) &&
634            (files[i].row == row)) {
635            foundID = i;
636            break;
637        }
638    }
639
640    // Found it in cache, just return
641    if (foundID != -1) {
642        OpenFile &of = files[foundID];
643
644        if (of.afile->isValid())
645        {
646            of.lastUsed = timeCount;
647            return of.afile;
648        }
649        else
650        {
651            if (of.afile)
652                delete of.afile;
653            of.afile = NULL;
654        }
655    }
656
657    // Didn't find it.  Need to reclaim one
658    // Look for the oldest used
659    int oldTime=-1,oldID=-1;
660    for (i=0;i<files.size();i++) {
661        OpenFile &of = files[i];
662        if (!of.afile || (oldTime == -1) || (of.lastUsed < oldTime)) {
663            oldID = i;
664            oldTime = of.lastUsed;
665            if (!of.afile)
666                break;
667        }
668    }
669
670
671    // Reclaim this one
672    OpenFile &of = files[oldID];
673    if (of.afile)
674        delete of.afile;
675    char fileName[1024];
676    if(col==-1) {
677        sprintf(fileName,"%s_%d.%s",baseName,id,ext);
678    }
679    else {
680        char dir[1024];
681        char filebase[1024];
682        //this is very ugly, but it avoids radical API changes
683        // find the last PATHSEPERATOR in the baseName string
684        int len = strlen(baseName);
685        while(--len > 0) {
686            if(baseName[len]==PATHSEPERATOR[0]) {
687                strcpy(filebase,&baseName[len+1]);
688                strcpy(dir,baseName);
689                dir[len]='\0';
690                break;
691            }
692        }
693        sprintf(fileName,"%s" PATHSEPERATOR "%d" PATHSEPERATOR "%d" PATHSEPERATOR "%s_%d.%s",
694                dir,col,row,filebase,id,ext);
695    }
696    of.afile = GetNewRAppFile(ness,fileName);
697    of.id = id;
698    of.row = row;
699    of.col = col;
700    of.lastUsed = timeCount;
701
702    timeCount++;
703
704    return of.afile;
705}
706
707// Constructor for OpenFile class
708trpgrAppFileCache::OpenFile::OpenFile()
709{
710    afile = NULL;
711    lastUsed = 0;
712    id = -1;
713}
Note: See TracBrowser for help on using the browser.