Made on Kubuntu
00001 // Copyright (C) 2009-2010 Ferdinand Majerech 00002 // This file is part of MiniINI 00003 // For conditions of distribution and use, see copyright notice in LICENSE.txt 00004 00005 #include <cstdio> 00006 #include <cstring> 00007 00008 #ifndef MINIINI_NO_STL 00009 #include <string> 00010 #endif 00011 00012 #include "typedefs.h" 00013 #include "globals.h" 00014 #include "log.h" 00015 #include "inisection.h" 00016 #include "inifile.h" 00017 #include "util.h" 00018 #include "inifileutil.h" 00019 #include "time.h" 00020 00021 00022 using namespace miniini_private; 00023 00024 bool INIFile::OpenFile(const char * const fname) 00025 { 00026 MINIINI_ASSERT(fname, "NULL pointer was passed as file name to" 00027 "INIFile::OpenFile()"); 00028 MINIINI_ASSERT(!IsValid(), "OpenFile() was called on an INIFile that is " 00029 "already loaded"); 00030 00031 #ifdef MINIINI_BENCH_EXTRA 00032 #ifdef linux 00033 ld ftimestart = GetTime(); 00034 #endif 00035 #endif 00036 00037 //opening file 00038 FILE * const file = fopen( fname, "rb" ); 00039 if(file == NULL) 00040 { 00041 MINIINI_ERROR("Couldn't open file. Maybe it does not exist? File: %s", 00042 fname); 00043 return false; 00044 } 00045 //determining filesize 00046 i seek = fseek(file, 0, SEEK_END); 00047 if(seek != 0) 00048 { 00049 fclose(file); 00050 MINIINI_ERROR("Couldn't reach end of file. File: %s", fname); 00051 return false; 00052 } 00053 const i size = ftell(file); 00054 if(size == -1) 00055 { 00056 fclose(file); 00057 MINIINI_ERROR("Couldn't determine size of file. File: %s", fname); 00058 return false; 00059 } 00060 seek = fseek(file, 0, SEEK_SET); 00061 if(seek!=0) 00062 { 00063 fclose(file); 00064 MINIINI_ERROR("Couldn't reach start of file. File: %s", fname); 00065 return false; 00066 } 00067 //reading file to a buffer 00068 c * const buf = new c [size + 1]; 00069 const i readnum = fread(buf, size, 1, file); 00070 fclose(file); 00071 00072 #ifdef MINIINI_BENCH_EXTRA 00073 #ifdef linux 00074 bench_filetime = GetTime() - ftimestart; 00075 #endif 00076 #endif 00077 00078 //if 0 blocks succesfully read 00079 if(readnum == 0) 00080 { 00081 delete [] buf; 00082 MINIINI_ERROR("Could open but could not read from file. File might be " 00083 "corrupted or you might not have sufficient rights to " 00084 "read from it. File: %s", fname); 00085 return false; 00086 } 00087 //adding trailing zero to the buffer 00088 buf[size] = 0; 00089 #ifdef MINIINI_BENCH_EXTRA 00090 #ifdef linux 00091 ld ltimestart = GetTime(); 00092 #endif 00093 #endif 00094 bool out = LoadBuffer(buf, static_cast<unsigned>(size + 1)); 00095 #ifdef MINIINI_BENCH_EXTRA 00096 #ifdef linux 00097 bench_loadtime = GetTime() - ltimestart; 00098 #endif 00099 #endif 00100 delete [] buf; 00101 return out; 00102 } 00103 00104 bool INIFile::LoadBuffer(const char * buf, unsigned size) 00105 { 00106 MINIINI_ASSERT(buf, "NULL pointer was passed as buffer to load from to" 00107 "INIFile::LoadBuffer()"); 00108 MINIINI_ASSERT(!IsValid(), "LoadBuffer() was called on an INIFile that is " 00109 "already loaded"); 00110 //Allocating memory for ini sections' strings in 16 blocks- 00111 //that results in a little speed overhead but potential memory 00112 //overhead of the allocator is decreased to a bit more than 00113 //1/16 of file size. 00114 Alloc = new Allocator(size, 16); 00115 //capacity of temporary buffer of pointers to sections 00116 ui tempsectionscap = 16; 00117 INISection::InitTempData(); 00118 //temporary buffer of pointers to sections 00119 INISection * * tempsections = new INISection * [tempsectionscap]; 00120 //ptr to the current character in buffer 00121 const c * currentchar = buf; 00122 //allocated capacity of headername 00123 ui headercap = 64; 00124 //buffer to load section header name to. 00125 c * headername = new c [headercap]; 00126 //number of chars in headername 00127 ui headersize; 00128 //Loading the default INI section 00129 INISection * newsection = new INISection(); 00130 newsection->Init("[DEFAULT]", ¤tchar, Alloc); 00131 Insert(tempsections, Length, newsection); 00132 ++Length; 00133 //Iterating through lines in buffer, reading sections found 00134 while(*currentchar != '\0') 00135 { 00136 //Header() leaves currentchar at start of next line 00137 headersize = Header(currentchar, headername, headercap); 00138 //header found 00139 if(headersize) 00140 { 00141 //if temp section ptrs buffer runs out of space, reallocate it 00142 if(Length + 1 > tempsectionscap) 00143 { 00144 MINIINI_REALLOCATE(tempsections, tempsectionscap, Length, INISection *); 00145 } 00146 //Try to load new section 00147 newsection = new INISection(); 00148 newsection->Init(headername, ¤tchar, Alloc); 00149 //Insert new section 00150 if(Insert(tempsections, Length, newsection)) 00151 { 00152 ++Length; 00153 } 00154 else 00155 { 00156 delete newsection; 00157 } 00158 } 00159 } 00160 delete [] headername; 00161 //Length is at least 1 due to the default section 00162 if(Length == 1) 00163 { 00164 MINIINI_WARNING("Empty INI file/buffer."); 00165 } 00166 //copy pointers from tempsections to Sections and delete tempsections 00167 Sections = new INISection * [Length]; 00168 memcpy(Sections, tempsections, Length * sizeof(INISection *)); 00169 delete [] tempsections; 00170 INISection::DestroyTempData(); 00171 //Remove any unused memory blocks from the allocator. 00172 Alloc->Trim(); 00173 return true; 00174 } 00175 00176 INIFile::~INIFile() 00177 { 00178 if(!IsValid()) 00179 { 00180 return; 00181 } 00182 for(ui section = 0; section < Length; ++section) 00183 { 00184 delete Sections[section]; 00185 } 00186 delete [] Sections; 00187 delete Alloc; 00188 } 00189 00190 INISection * INIFile::GetSection(const char * const name) const 00191 { 00192 MINIINI_ASSERT(name, "NULL pointer was passed as section name to" 00193 "INIFile::GetSection()"); 00194 i sectionidx; 00195 //if an empty string ("") is passed, we're using the section that the 00196 //iteration index points to 00197 if(*name == '\0') 00198 { 00199 MINIINI_ASSERT(Iter >= static_cast<i>(0) && Iter < static_cast<i>(Length), 00200 "Called INIFile::GetSection() with iteration index out" 00201 "of range"); 00202 sectionidx = Iter; 00203 } 00204 else 00205 { 00206 sectionidx = BinarySearch(Sections, Length, name); 00207 } 00208 if(sectionidx >= 0) 00209 { 00210 return Sections[sectionidx]; 00211 } 00212 MINIINI_ERROR("Missing requested section. Section: %s", name); 00213 return NULL; 00214 } 00215