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