Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

datafile_inputprovider.cpp

Go to the documentation of this file.
00001 /*
00002         $Id: datafile_inputprovider.cpp,v 1.3 2001/01/30 23:34:05 mbn Exp $
00003 
00004         ------------------------------------------------------------------------
00005         ClanLib, the platform independent game SDK.
00006 
00007         This library is distributed under the GNU LIBRARY GENERAL PUBLIC LICENSE
00008         version 2. See COPYING for details.
00009 
00010         For a total list of contributers see CREDITS.
00011 
00012         ------------------------------------------------------------------------
00013 
00014         File purpose:
00015                 Datafile input source provider, part of the i/o data component.
00016 
00017 */
00018 
00019 #include "Core/precomp.h"
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <iostream>
00024 #include <string.h>
00025 
00026 #ifndef WIN32
00027 #include <unistd.h>
00028 #else
00029 #include <io.h>
00030 #endif
00031 
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <fcntl.h>
00035 
00036 #include "datafile_inputprovider.h"
00037 #include "API/Core/System/error.h"
00038 
00039 
00040 CL_InputSourceProvider *CL_InputSourceProvider::create_datafile_provider(const char *filename)
00041 {
00042         return new CL_InputSourceProvider_Datafile(filename);
00043 }
00044 
00045 
00046 CL_InputSourceProvider_Datafile::CL_InputSourceProvider_Datafile(const char *_datafile)
00047 {
00048         datafile = _datafile;
00049 }
00050 
00051 CL_InputSource *CL_InputSourceProvider_Datafile::open_source(const char *filename)
00052 {
00053         return new CL_InputSource_Datafile(filename, datafile.c_str());
00054 }
00055 
00056 CL_InputSourceProvider *CL_InputSourceProvider_Datafile::clone()
00057 {
00058         return new CL_InputSourceProvider_Datafile(datafile.c_str());
00059 }
00060 
00061 /**************************
00062         CL_InputSource_Datafile
00063 **************************/
00064 
00065 #ifdef WIN32
00066         #define OPENFLAGS O_RDONLY|O_BINARY
00067 #else
00068         #define OPENFLAGS O_RDONLY
00069 #endif
00070 
00071 char datafile_id[]="ClanSoft datafile version 3.0";
00072 
00073 CL_InputSource_Datafile::CL_InputSource_Datafile(
00074         const char *_filename, const char *_datafile)
00075 {
00076         filename = _filename;
00077         datafile = _datafile;
00078 
00079         datafile_open = 0;
00080         index_open = 0;
00081 
00082         open();
00083 }
00084 
00085 CL_InputSource_Datafile::CL_InputSource_Datafile(const CL_InputSource_Datafile *source)
00086 {
00087         filename = source->filename;
00088         datafile = source->datafile;
00089 
00090         datafile_open = 0;
00091         index_open = 0;
00092 
00093         open();
00094 }
00095 
00096 CL_InputSource_Datafile::~CL_InputSource_Datafile()
00097 {
00098         close();
00099 }
00100 
00101 void CL_InputSource_Datafile::set_system_mode()
00102 {
00103   throw CL_Error("CL_InputSource_Datafile::set_system_mode() is not yet implemented");
00104         // BUG BUG: Not implemented!!!
00105 }
00106 
00107 void CL_InputSource_Datafile::set_big_endian_mode()
00108 {
00109   throw CL_Error("CL_InputSource_Datafile::set_big_endian_mode() is not yet implemented");
00110         // BUG BUG: Not implemented!!!
00111 }
00112 
00113 void CL_InputSource_Datafile::set_little_endian_mode()
00114 {
00115         // BUG BUG: Not implemented!!!
00116 }
00117 
00118 int CL_InputSource_Datafile::read_int32()
00119 {
00120         int svar;
00121 
00122         if (gzread(gzfile, &svar, sizeof(int))!=sizeof(int))
00123         {
00124                 throw CL_Error("CL_InputSource_Datafile::read_int32() failed");
00125         }
00126 
00127         seek_pos+=sizeof(int);
00128         return svar;
00129 }
00130 
00131 unsigned int CL_InputSource_Datafile::read_uint32()
00132 {
00133         unsigned int svar;
00134 
00135         if (gzread(gzfile, &svar, sizeof(unsigned int))!=sizeof(unsigned int))
00136         {
00137                 throw CL_Error("CL_InputSource_Datafile::read_uint32() failed");
00138         }
00139 
00140         seek_pos+=sizeof(unsigned int);
00141         return svar;
00142 }
00143 
00144 short CL_InputSource_Datafile::read_short16()
00145 {
00146         short svar;
00147 
00148         if (gzread(gzfile, &svar, sizeof(short))!=sizeof(short))
00149         {
00150                 throw CL_Error("CL_InputSource_Datafile::read_short16() failed");
00151         }
00152 
00153         seek_pos+=sizeof(short);
00154         return svar;
00155 }
00156 
00157 unsigned short CL_InputSource_Datafile::read_ushort16()
00158 {
00159         unsigned short svar;
00160 
00161         if (gzread(gzfile, &svar, sizeof(unsigned short))!=sizeof(unsigned short))
00162         {
00163                 throw CL_Error("CL_InputSource_Datafile::read_ushort16() failed");
00164         }
00165 
00166         seek_pos+=sizeof(unsigned short);
00167         return svar;
00168 }
00169 
00170 char CL_InputSource_Datafile::read_char8()
00171 {
00172         char svar;
00173 
00174         if (gzread(gzfile, &svar, sizeof(char))!=sizeof(char))
00175         {
00176                 throw CL_Error("CL_InputSource_Datafile::read_char8() failed");
00177         }
00178 
00179         seek_pos += sizeof(char);
00180         return svar;
00181 }
00182 
00183 unsigned char CL_InputSource_Datafile::read_uchar8()
00184 {
00185         unsigned char svar;
00186 
00187         if (gzread(gzfile, &svar, sizeof(unsigned char))!=sizeof(unsigned char))
00188         {
00189                 throw CL_Error("CL_InputSource_Datafile::read_uchar8() failed");
00190         }
00191 
00192         seek_pos += sizeof(unsigned char);
00193         return svar;
00194 }
00195 
00196 float CL_InputSource_Datafile::read_float32()
00197 {
00198         float svar;
00199 
00200         if (gzread(gzfile, &svar, sizeof(float))!=sizeof(float))
00201         {
00202                 throw CL_Error("CL_InputSource_Datafile::read_float32() failed");
00203         }
00204                 
00205         seek_pos += sizeof(float);
00206         return svar;
00207 }
00208 
00209 int CL_InputSource_Datafile::read(void *addr, int size)
00210 {
00211         int svar = gzread(gzfile, addr, size);
00212         seek_pos += svar;
00213         return svar;
00214 }
00215 
00216 void CL_InputSource_Datafile::open()
00217 {
00218         if (datafile_open) return;
00219         datafile_handle = ::open(datafile.c_str(), OPENFLAGS);
00220 
00221         if (datafile_handle == -1)
00222         {
00223                 std::string err("Could not open datafile ");
00224                 err += std::string(datafile);
00225                 throw CL_Error(err.c_str());
00226         }
00227 
00228         int id_len = strlen(datafile_id);
00229 
00230         char *temp = new char[id_len+1];
00231 
00232         ::read(datafile_handle, temp, id_len);
00233 
00234         temp[id_len] = 0;
00235 
00236         if (strcmp(temp, datafile_id) != 0)
00237         {
00238                 ::close(datafile_handle);
00239                 datafile_handle = -1;
00240 
00241                 throw CL_Error("Invalid datafile format");
00242 //              cout << "Invalid datafile format: " << temp << " (expected: " << datafile_id << ")" << endl;
00243 //              cl_assert(1==0);
00244         }
00245 
00246         delete temp;
00247 
00248         datafile_open = 1;
00249         open_index();
00250 //      cout << "open complete" << endl;
00251 }
00252 
00253 void CL_InputSource_Datafile::close()
00254 {
00255         if (datafile_open == 0) return;
00256 
00257         close_index();
00258         ::close(datafile_handle);
00259 
00260         datafile_open = 0;
00261 }
00262 
00263 void CL_InputSource_Datafile::open_index()
00264 {
00265         if (index_open != 0) close_index();
00266 
00267         lseek(datafile_handle, strlen(datafile_id), SEEK_SET);  // Skip file ID
00268         int index_pos;
00269         ::read(datafile_handle, &index_pos, sizeof(int));
00270         lseek(datafile_handle, index_pos, SEEK_SET);
00271 
00272 //      cout << "Searching for " << filename << endl;
00273 
00274         int num_indexes = 0;
00275         ::read(datafile_handle, &num_indexes, sizeof(int));
00276         for (int i=0; i<num_indexes; i++)
00277         {
00278                 short length;
00279                 ::read(datafile_handle, &length,sizeof(short));
00280 
00281                 char *objname = new char[length];
00282                 int objpos;
00283 
00284                 ::read(datafile_handle, objname, length);
00285                 ::read(datafile_handle, &objpos, sizeof(int));
00286                 ::read(datafile_handle, &objsize, sizeof(int));
00287 
00288 //              cout << "Found index: " << objname << endl;
00289 
00290                 if (strcmp(objname, filename.c_str()) == 0)
00291                 {
00292                         lseek(datafile_handle, objpos, SEEK_SET);
00293 
00294                         gzfile = gzdopen(dup(datafile_handle), "rb");
00295                         index_open = 1;
00296                         seek_pos = 0;
00297 
00298                         delete[] objname;
00299                         return;
00300                 }
00301 
00302                 delete[] objname;
00303         }
00304 
00305         index_open = 0;
00306 
00307         std::string err("ClanLib: Couldn't find datafile index: ");
00308         err += std::string(filename);
00309         throw CL_Error(err);
00310 }
00311 
00312 void CL_InputSource_Datafile::close_index()
00313 {
00314         if (index_open==0) return;
00315 
00316         gzclose(gzfile);
00317         index_open=0;
00318 }
00319 
00320 CL_InputSource *CL_InputSource_Datafile::clone() const
00321 {
00322         return new CL_InputSource_Datafile(this);
00323 }
00324 
00325 int CL_InputSource_Datafile::tell() const
00326 {
00327         return seek_pos;
00328 }
00329 
00330 void CL_InputSource_Datafile::seek(int pos, SeekEnum seek_type)
00331 {
00332         if (seek_type == seek_cur)
00333         {
00334                 if (pos > 0)
00335                 {
00336                         char *temp = new char[pos];
00337                         read(temp, pos);
00338                         delete temp;
00339                 }
00340                 else if (pos < 0)
00341                 {
00342                         seek(tell()+pos, seek_set);
00343                 }
00344                 return;
00345         }
00346         else if (seek_type == seek_set)
00347         {
00348                 int cur_pos = tell();
00349                 if (pos >= cur_pos)
00350                 {
00351                         seek(pos - cur_pos, seek_cur);
00352                         return;
00353                 }
00354         }
00355 
00356         /*
00357          * Now this is a special case, we allow back seeking exceptionnaly
00358          * when the absolute pos is 0, in fact what we do is just close
00359          * and then re-open the file. It's usefull for MikMod for instance,
00360          * since MikMod needs to try several loaders before it finds the
00361          * right file format.
00362          */
00363         if (seek_type == seek_set && pos == 0)
00364         {
00365                 close();
00366                 open();
00367                 return;
00368         } 
00369 
00370         std::cout << "ClanLib: seek() in datafiles only supports forward seeks" << std::endl;
00371         cl_assert(false);
00372 }
00373 
00374 int CL_InputSource_Datafile::size() const
00375 {
00376         return objsize;
00377 }
00378 
00379 std::string CL_InputSource_Datafile::read_string()
00380 {
00381         int size = read_int32();
00382 
00383         char *str = new char[size];
00384         read(str, size);
00385         
00386         std::string ret = str;
00387         delete[] str;
00388 
00389         return ret;
00390 }
00391 
00392 void CL_InputSource_Datafile::push_position()
00393 {
00394         CL_Zipped_Position indexpos;
00395 
00396         indexpos.gzfile = gzfile;
00397         indexpos.datafile_pos = lseek(datafile_handle, 0, SEEK_CUR);
00398         indexpos.seek_pos = seek_pos;
00399 
00400         index_stack.push(indexpos);
00401 
00402         index_open=0;
00403 }
00404 
00405 void CL_InputSource_Datafile::pop_position()
00406 {
00407         if (index_open != 0) close_index();
00408 
00409         index_open = 1;
00410 
00411         CL_Zipped_Position pushed_index = index_stack.top();
00412         index_stack.pop();
00413         
00414         gzfile = pushed_index.gzfile;
00415         lseek(datafile_handle, pushed_index.datafile_pos, SEEK_SET);
00416         seek_pos = pushed_index.seek_pos;
00417 }

Generated at Wed Apr 4 19:53:59 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001