Add support for displaying level names and authors
[numtypysics.git] / Levels.cpp
blob8b7ce987ec7de09966c6a808b7f65253915eb753
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.
17 #include <cstring>
18 #include <sys/types.h>
19 #include <dirent.h>
21 #include "Levels.h"
22 #include "ZipFile.h"
23 #include "Os.h"
25 using namespace std;
27 static int rankFromPath( const string& p, int defaultrank=9999 )
29 const char *c = p.data();
30 size_t i = p.rfind(Os::pathSep);
31 if ( i != string::npos ) {
32 c += i+1;
33 if ( *c++=='L' ){
34 int rank=0;
35 while ( *c>='0' && *c<='9' ) {
36 rank = rank*10 + (*c)-'0';
37 c++;
39 return rank;
42 return defaultrank;
45 Levels::Levels( int numFiles, const char** names )
47 for ( int d=0;d<numFiles;d++ ) {
48 addPath( names[d] );
52 bool Levels::addPath( const char* path )
54 int len = strlen( path );
55 if ( strcasecmp( path+len-4, ".npz" )==0 ) {
56 scanCollection( string(path), rankFromPath(path) );
57 } else if ( strcasecmp( path+len-4, ".nph" )==0 ) {
58 addLevel( path, rankFromPath(path) );
59 } else {
60 DIR *dir = opendir( path );
61 if ( dir ) {
62 struct dirent* entry;
63 while ( (entry = readdir( dir )) != NULL ) {
64 if ( entry->d_name[0] != '.' ) {
65 string full( path );
66 full += "/";
67 full += entry->d_name;
68 //DANGER - recursion may not halt for linked dirs
69 addPath( full.c_str() );
72 closedir( dir );
73 } else {
74 printf("bogus level path %s\n",path);
77 return true;
80 bool Levels::addLevel( const string& file, int rank, int index )
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;
94 printf("top level %s\n",file.c_str());
95 m_levels.append( e );
96 return true;
100 bool Levels::scanCollection( const std::string& file, int rank )
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 );
107 return false;
110 int Levels::numLevels()
112 return m_levels.size();
116 int Levels::load( int i, unsigned char* buf, int bufLen )
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 );
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);
135 return l;
137 throw "invalid level index";
141 std::string Levels::levelName( int i )
143 std::string s = "end";
144 if ( i < m_levels.size() ) {
145 if ( m_levels[i]->index >= 0 ) {
146 ZipFile zf( m_levels[i]->file.c_str() );
147 s = zf.entryName( m_levels[i]->index );
148 } else {
149 s = m_levels[i]->file;
152 size_t j = s.rfind(Os::pathSep);
153 size_t k = s.rfind('.');
154 return s.substr(j+1,k-j-1);
157 #if 0
158 const std::string& Levels::levelFile( int i )
160 if ( i < m_levels.size() ) {
161 return m_levels[i]->file;
163 throw "invalid level index";
165 #endif
168 int Levels::findLevel( const char *file )
170 for ( int i=0; i<m_levels.size(); i++ ) {
171 if ( m_levels[i]->file == file ) {
172 return i;
175 return -1;