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 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 bool out = LoadBuffer(buf, static_cast<unsigned>(size + 1)); 00090 delete [] buf; 00091 return out; 00092 } 00093 00094 bool INIFile::LoadBuffer(const char * buf, unsigned size) 00095 { 00096 MINIINI_ASSERT(buf, "NULL pointer was passed as buffer to load from to" 00097 "INIFile::LoadBuffer()"); 00098 MINIINI_ASSERT(!IsValid(), "LoadBuffer() was called on an INIFile that is " 00099 "already loaded"); 00100 //Allocating memory for ini sections' strings in 16 blocks- 00101 //that results in a little speed overhead but potential memory 00102 //overhead of the allocator is decreased to a bit more than 00103 //1/16 of file size. 00104 Alloc = new Allocator(size, 16); 00105 //capacity of temporary buffer of pointers to sections 00106 ui tempsectionscap = 16; 00107 INISection::InitTempData(); 00108 //temporary buffer of pointers to sections 00109 INISection * * tempsections = new INISection * [tempsectionscap]; 00110 //ptr to the current character in buffer 00111 const c * currentchar = buf; 00112 //allocated capacity of headername 00113 ui headercap = 64; 00114 //buffer to load section header name to. 00115 c * headername = new c [headercap]; 00116 //number of chars in headername 00117 ui headersize; 00118 //Loading the default INI section 00119 INISection * newsection = new INISection(); 00120 newsection->Init("[DEFAULT]", ¤tchar, Alloc); 00121 Insert(tempsections, Length, newsection); 00122 ++Length; 00123 //Iterating through lines in buffer, reading sections found 00124 while(*currentchar != '\0') 00125 { 00126 //Header() leaves currentchar at start of next line 00127 headersize = Header(currentchar, headername, headercap); 00128 //header found 00129 if(headersize) 00130 { 00131 //if temp section ptrs buffer runs out of space, reallocate it 00132 if(Length + 1 > tempsectionscap) 00133 { 00134 MINIINI_REALLOCATE(tempsections, tempsectionscap, Length, INISection *); 00135 } 00136 //Try to load new section 00137 newsection = new INISection(); 00138 newsection->Init(headername, ¤tchar, Alloc); 00139 //Insert new section 00140 if(Insert(tempsections, Length, newsection)) 00141 { 00142 ++Length; 00143 } 00144 else 00145 { 00146 delete newsection; 00147 } 00148 } 00149 } 00150 delete [] headername; 00151 //Length is at least 1 due to the default section 00152 if(Length == 1) 00153 { 00154 MINIINI_WARNING("Empty INI file/buffer."); 00155 } 00156 //copy pointers from tempsections to Sections and delete tempsections 00157 Sections = new INISection * [Length]; 00158 memcpy(Sections, tempsections, Length * sizeof(INISection *)); 00159 delete [] tempsections; 00160 INISection::DestroyTempData(); 00161 //Remove any unused memory blocks from the allocator. 00162 Alloc->Trim(); 00163 return true; 00164 } 00165 00166 INIFile::~INIFile() 00167 { 00168 if(!IsValid()) 00169 { 00170 return; 00171 } 00172 for(ui section = 0; section < Length; ++section) 00173 { 00174 delete Sections[section]; 00175 } 00176 delete [] Sections; 00177 delete Alloc; 00178 } 00179 00180 INISection * INIFile::GetSection(const char * const name) const 00181 { 00182 MINIINI_ASSERT(name, "NULL pointer was passed as section name to" 00183 "INIFile::GetSection()"); 00184 i sectionidx; 00185 //if an empty string ("") is passed, we're using the section that the 00186 //iteration index points to 00187 if(*name == '\0') 00188 { 00189 MINIINI_ASSERT(Iter >= static_cast<i>(0) && Iter < static_cast<i>(Length), 00190 "Called INIFile::GetSection() with iteration index out" 00191 "of range"); 00192 sectionidx = Iter; 00193 } 00194 else 00195 { 00196 sectionidx = BinarySearch(Sections, Length, name); 00197 } 00198 if(sectionidx >= 0) 00199 { 00200 return Sections[sectionidx]; 00201 } 00202 MINIINI_ERROR("Missing requested section. Section: %s", name); 00203 return NULL; 00204 } 00205