00001
00007 #include <limits.h>
00008 #include <stdbool.h>
00009 #include <stddef.h>
00010 #include <stdint.h>
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <strings.h>
00014
00015 #include "check.h"
00016 #include "db5_dat.h"
00017 #include "db5_hdr.h"
00018 #include "db5_index.h"
00019 #include "db5_types.h"
00020 #include "file.h"
00021 #include "crc32.h"
00022 #include "logger.h"
00023
00024
00026 #define byteof(c,i) (((char *)&c)[(i)])
00027
00028
00030 typedef struct
00031 {
00033 uint32_t hidden;
00035 uint32_t position;
00037 uint32_t uid;
00038 } index_entry;
00039
00040
00042 static char *index_master_data;
00043
00045 static uint32_t index_entry_size;
00046
00047
00048
00055 static int db5_index_compare_entries(const void *entry1, const void *entry2)
00056 {
00057 uint32_t pos1, pos2;
00058
00059 check(entry1 != NULL);
00060 check(entry2 != NULL);
00061
00062 pos1 = ((index_entry *)entry1)->position;
00063 pos2 = ((index_entry *)entry2)->position;
00064
00065 return memcmp(index_master_data+pos1*index_entry_size, index_master_data+pos2*index_entry_size, index_entry_size);
00066 }
00067
00073 static void index_dump_table(const index_entry *entries, const uint32_t count)
00074 {
00075 uint32_t i;
00076
00077 for(i=0; i < count; i++)
00078 {
00079 add_log(ADDLOG_DUMP, "[db5/index]index_col", " - [%08x] %u\n", entries[i].uid, entries[i].position);
00080 }
00081 }
00082
00083
00084 bool db5_index_index_column(const ptrdiff_t reloffset, const size_t size, const uint32_t code)
00085 {
00086 char filename[PATH_MAX];
00087 db5_row row;
00088 FILE *file;
00089 uint32_t count, i;
00090 index_entry *entries;
00091
00092 check(reloffset < sizeof(db5_row));
00093 check(reloffset+size <= sizeof(db5_row));
00094
00095 add_log(ADDLOG_DEBUG, "[db5/index]index_col", "generating index for code '%c%c%c%c'\n",
00096 byteof(code, 0), byteof(code, 1), byteof(code, 2), byteof(code, 3));
00097
00098
00099 snprintf(filename, sizeof(filename), CONFIG_DB5_IDX_FILE, byteof(code, 0), byteof(code, 1), byteof(code, 2), byteof(code, 3));
00100 file = file_fcaseopen(CONFIG_DB5_DATA_DIR, filename, "wb");
00101 if (file == NULL)
00102 {
00103 add_log(ADDLOG_FAIL, "[db5/index]index_col", "unable to generate index file\n");
00104 return false;
00105 }
00106
00107
00108 count = db5_hdr_count();
00109 if (count == 0)
00110 {
00111 add_log(ADDLOG_NOTICE, "[db5/index]index_col", "no data to index\n");
00112 fclose(file);
00113 return false;
00114 }
00115
00116
00117 index_master_data = (char *)malloc(size*count);
00118 if (index_master_data == NULL)
00119 {
00120 add_log(ADDLOG_FAIL, "[db5/index]index_col", "not enought memory (%u entries)\n", count);
00121 fclose(file);
00122 return false;
00123 }
00124
00125 entries = (index_entry *)malloc(sizeof(index_entry)*count);
00126 if (entries == NULL)
00127 {
00128 add_log(ADDLOG_FAIL, "[db5/index]index_col", "not enought memory (%u entries)\n", count);
00129 free(index_master_data), fclose(file);
00130 return false;
00131 }
00132
00133
00134 index_entry_size = size;
00135
00136 for(i=0; i < count; i++)
00137 {
00138 if (!db5_dat_select_row(i, &row))
00139 {
00140 add_log(ADDLOG_FAIL, "[db5/index]index_col", "unable to read entry %u\n", i);
00141 free(index_master_data), free(entries), fclose(file);
00142 return false;
00143 }
00144 memcpy(index_master_data+i*size, ((char *)&row)+reloffset, size);
00145
00146 entries[i].hidden = row.hidden;
00147 entries[i].position = i;
00148 }
00149
00150
00151 if (size <= membersizeof(index_entry, uid))
00152 {
00153 for(i=0; i < count; i++)
00154 {
00155 entries[i].uid = 0;
00156 memcpy(&entries[i].uid, index_master_data+i*size, size);
00157 }
00158 }
00159 else
00160 {
00161 for(i=0; i < count; i++)
00162 {
00163 entries[i].uid = crc32(index_master_data+i*size, size);
00164 }
00165 }
00166
00167
00168 qsort(entries, count, sizeof(index_entry), db5_index_compare_entries);
00169
00170 #ifdef DEBUG
00171 index_dump_table(entries, count);
00172 #endif
00173
00174
00175 if (fwrite(entries, sizeof(index_entry), count, file) != count)
00176 {
00177 add_log(ADDLOG_FAIL, "[db5/index]index_col", "unable to wire index data to file '%s'\n", filename);
00178 free(index_master_data), free(entries), fclose(file);
00179 return false;
00180 }
00181
00182 free(index_master_data);
00183 free(entries);
00184 fclose(file);
00185
00186 add_log(ADDLOG_DEBUG, "[db5/index]index_col", "done.\n");
00187
00188 return true;
00189 }
00190