1 /*
2  * This file is part of NumptyPhysics
3  * Copyright (C) 2008 Tim Edmonds
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 3 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  */
16 
17 #include <cstring>
18 #include <sys/types.h>
19 #include <dirent.h>
20 
21 #include "Levels.h"
22 #include "ZipFile.h"
23 
24 using namespace std;
25 
rankFromPath(const string & p,int defaultrank=9999)26 static int rankFromPath( const string& p, int defaultrank=9999 )
27 {
28   const char *c = p.data();
29   size_t i = p.rfind('/');
30   if ( i != string::npos ) {
31     c += i+1;
32     if ( *c++=='L' ){
33       int rank=0;
34       while ( *c>='0' && *c<='9' ) {
35 	rank = rank*10 + (*c)-'0';
36 	c++;
37       }
38       return rank;
39     }
40   }
41   return defaultrank;
42 }
43 
Levels(int numFiles,const char ** names)44 Levels::Levels( int numFiles, const char** names )
45 {
46   for ( int d=0;d<numFiles;d++ ) {
47     addPath( names[d] );
48   }
49 }
50 
addPath(const char * path)51 bool Levels::addPath( const char* path )
52 {
53   int len = strlen( path );
54   if ( strcasecmp( path+len-4, ".npz" )==0 ) {
55     scanCollection( string(path), rankFromPath(path) );
56   } else if ( strcasecmp( path+len-4, ".nph" )==0 ) {
57     addLevel( path, rankFromPath(path) );
58   } else {
59     DIR *dir = opendir( path );
60     if ( dir ) {
61       struct dirent* entry;
62       while ( (entry = readdir( dir )) != NULL ) {
63 	if ( entry->d_name[0] != '.' ) {
64 	  string full( path );
65 	  full += "/";
66 	  full += entry->d_name;
67 	  int n = strlen( entry->d_name );
68 	  //DANGER - recursion may not halt for linked dirs
69 	  addPath( full.c_str() );
70 	}
71       }
72       closedir( dir );
73     } else {
74       printf("bogus level path %s\n",path);
75     }
76   }
77   return true;
78 }
79 
addLevel(const string & file,int rank,int index)80 bool Levels::addLevel( const string& file, int rank, int index )
81 {
82   LevelDesc *e = new LevelDesc( file, rank, index );
83   for ( int i=0; i<m_levels.size(); i++ ) {
84     if ( m_levels[i]->file == file
85 	 && m_levels[i]->index == index ) {
86       printf("addLevel %s already present!\n",file.c_str());
87       return false;
88     } else if ( m_levels[i]->rank > rank ) {
89       printf("addLevel %s at %d\n",file.c_str(),i);
90       m_levels.insert(i,e);
91       return true;
92     }
93   }
94   printf("top level %s\n",file.c_str());
95   m_levels.append( e );
96   return true;
97 }
98 
99 
scanCollection(const std::string & file,int rank)100 bool Levels::scanCollection( const std::string& file, int rank )
101 {
102   ZipFile zf(file);
103   printf("found collection %s with %d levels\n",file.c_str(),zf.numEntries());
104   for ( int i=0; i<zf.numEntries(); i++ ) {
105     addLevel( file, rankFromPath(zf.entryName(i),rank), i );
106   }
107   return false;
108 }
109 
numLevels()110 int Levels::numLevels()
111 {
112   return m_levels.size();
113 }
114 
115 
load(int i,unsigned char * buf,int bufLen)116 int Levels::load( int i, unsigned char* buf, int bufLen )
117 {
118   int l=0;
119   if ( i < m_levels.size() ) {
120     if ( m_levels[i]->index >= 0 ) {
121       ZipFile zf( m_levels[i]->file.c_str() );
122       if ( m_levels[i]->index < zf.numEntries() ) {
123 	unsigned char* d = zf.extract( m_levels[i]->index, &l);
124 	if ( d && l <= bufLen ) {
125 	  memcpy( buf, d, l );
126 	}
127       }
128     } else {
129       FILE *f = fopen( m_levels[i]->file.c_str(), "rt" );
130       if ( f ) {
131 	l = fread( buf, 1, bufLen, f );
132 	fclose(f);
133       }
134     }
135     return l;
136   }
137   throw "invalid level index";
138 
139 }
140 
141 #if 0
142 const std::string& Levels::levelFile( int i )
143 {
144   if ( i < m_levels.size() ) {
145     return m_levels[i]->file;
146   }
147   throw "invalid level index";
148 }
149 #endif
150 
151 
findLevel(const char * file)152 int Levels::findLevel( const char *file )
153 {
154   for ( int i=0; i<m_levels.size(); i++ ) {
155     if ( m_levels[i]->file == file ) {
156       return i;
157     }
158   }
159   return -1;
160 }
161 
162 
163