property.cpp

00001 /*
00002   nettyping のプロパティ情報管理
00003   Satofumi KAMIMURA
00004   $Id$
00005 */
00006 
00007 #include "property.h"
00008 #include "fileUtils.h"
00009 #include <libxml/tree.h>
00010 
00011 
00012 Property::Property(void)
00013   : loaded_file(""), selected_index(0), pre_tag(BAD_CAST ""), user(NULL) {
00014 
00015   sys.fullscreen = false;
00016   sys.user_index = 0;
00017   LIBXML_TEST_VERSION;
00018 }
00019 
00020 
00021 Property::~Property(void) {
00022   if (!loaded_file.empty()) {
00023     save();
00024   }
00025 }
00026 
00027 
00028 bool Property::readXMLLine(xml_t& xml, xmlTextReaderPtr reader) {
00029   xml.depth = -1;
00030   if (xmlTextReaderRead(reader) != 1) {
00031     return false;
00032   }
00033 
00034   xml.type = xmlTextReaderNodeType(reader);
00035   if (xml.type == XML_READER_TYPE_END_ELEMENT) {
00036     pre_tag = BAD_CAST "";
00037   }
00038   xml.depth = xmlTextReaderDepth(reader);
00039 
00040   const xmlChar* tag_name = xmlTextReaderConstName(reader);
00041   if (tag_name && (xml.type == XML_READER_TYPE_ELEMENT)) {
00042     xml.tag = tag_name;
00043     pre_tag = tag_name;
00044   } else {
00045     xml.tag = pre_tag;
00046   }
00047   const xmlChar* value_name = xmlTextReaderConstValue(reader);
00048   xml.value = (value_name) ? value_name : BAD_CAST "";
00049 
00050   return true;
00051 }
00052 
00053 
00054 void Property::readSysInfo(xmlTextReaderPtr reader) {
00055   bool ret;
00056   xml_t xml;
00057   do {
00058     ret = readXMLLine(xml, reader);
00059     //printf("%d, %d, %s, %s\n", xml.type, xml.depth, xml.tag, xml.value);
00060     if (xml.depth < 2) {
00061       continue;
00062     }
00063 
00064     if (!xmlStrcmp(BAD_CAST "fullscreen", xml.tag)) {
00065       // 画面モードの読み出し
00066       sys.fullscreen = !xmlStrcmp(BAD_CAST "true", xml.value) ? true : false;
00067 
00068     } else if (!xmlStrcmp(BAD_CAST "user_index", xml.tag)) {
00069       // デフォルト選択のユーザ番号読み出し
00070       selected_index = atoi((char*)(BAD_CAST xml.value));
00071     }
00072   } while (ret &&
00073            !((xml.depth < 2) && (xml.type == XML_READER_TYPE_END_ELEMENT)));
00074 }
00075 
00076 
00077 void Property::setUserIndex(unsigned int index) {
00078   sys.user_index = index;
00079   if (sys.user_index >= users.size()) {
00080     sys.user_index = 0;
00081   }
00082   user = &users[sys.user_index];
00083 }
00084 
00085 
00086 int Property::addUser(const char* name) {
00087   if (users.size() >= UserMax) {
00088     return UsersNumOver;
00089   }
00090 
00091   if (strlen(name) <= 0) {
00092     return InvalidName;
00093   }
00094 
00095   for (std::vector<userInfo_t>::iterator it = users.begin();
00096        it != users.end(); ++it) {
00097     if (!it->name.compare(name)) {
00098       return AlreadyExist;
00099     }
00100   }
00101 
00102   // ユーザの追加
00103   userInfo_t add;
00104   add.name = name;
00105 
00106   bool empty = users.empty();
00107   users.push_back(add);
00108   if (empty) {
00109     setUserIndex(0);
00110   }
00111   return 0;
00112 }
00113 
00114 
00115 void Property::delUser(unsigned int index) {
00116   if (index >= users.size()) {
00117     return;
00118   }
00119   if (sys.user_index > index) {
00120     --sys.user_index;
00121   } else if (sys.user_index == index) {
00122     sys.user_index = 0;
00123   }
00124   users.erase(users.begin() + index);
00125   setUserIndex(sys.user_index);
00126 }
00127 
00128 
00129 void Property::readAllUserInfo(xmlTextReaderPtr reader) {
00130   bool ret;
00131   xml_t xml;
00132   do {
00133     userInfo_t add;
00134     bool added = false;
00135     do {
00136       ret = readXMLLine(xml, reader);
00137       //printf("%d, %d, %s, %s\n", xml.type, xml.depth, xml.tag, xml.value);
00138 
00139       if (!xmlStrcmp(BAD_CAST "name", xml.tag)) {
00140         // ユーザ名の読み出し
00141         add.name = (char*)(xml.value);
00142         added = true;
00143 
00144       } else if (!xmlStrcmp(BAD_CAST "practice_num", xml.tag)) {
00145         // 出題数の読み出し
00146         add.practice_num = atoi((char*)(BAD_CAST xml.value));
00147 
00148       } else if (!xmlStrcmp(BAD_CAST "roman_convert", xml.tag)) {
00149         // 変換モードの読み出し
00150         add.roman_convert = !xmlStrcmp(BAD_CAST "true", xml.value)? true:false;
00151 
00152       } else if (!xmlStrcmp(BAD_CAST "auto_next", xml.tag)) {
00153         // 自動改ページかの読み出し
00154         add.auto_next = !xmlStrcmp(BAD_CAST "true", xml.value)? true : false;
00155 
00156       } else if (!xmlStrcmp(BAD_CAST "learn_mode", xml.tag)) {
00157         // 覚えようモードかの読み出し
00158         add.learn_mode = !xmlStrcmp(BAD_CAST "true", xml.value)? true : false;
00159 
00160       } else if (!xmlStrcmp(BAD_CAST "send_ranking", xml.tag)) {
00161         // ランキング登録するかの読み出し
00162         add.send_ranking = !xmlStrcmp(BAD_CAST "true", xml.value)? true :false;
00163 
00164       } else if (!xmlStrcmp(BAD_CAST "rank_page", xml.tag)) {
00165         // ランキングの登録先
00166         add.rank_page = (char*)(xml.value);
00167       }
00168     } while (ret && (xml.depth >= 3));
00169     if (added) {
00170       users.push_back(add);
00171     }
00172   } while (ret &&
00173            !((xml.depth < 2) && (xml.type == XML_READER_TYPE_END_ELEMENT)));
00174 }
00175 
00176 
00177 bool Property::load(const char* file, const char* path[]) {
00178 
00179   // ファイルパスの決定
00180   std::string full_path = VXV::searchFile(file, path);
00181 
00182   // 設定ファイルの新規作成
00183   if (full_path.size() <= 0) {
00184     int last_index = 0;
00185     while (path[last_index]) {
00186       ++last_index;
00187     }
00188     for (int i = last_index -1; i >= 0; --i) {
00189       if (VXV::createDirs(path[i]) < 0) {
00190         continue;
00191       }
00192       full_path = std::string(path[i]) + '/' + file;
00193       if (save(full_path.c_str())) {
00194         break;
00195       }
00196     }
00197   }
00198 
00199   xmlTextReaderPtr reader = xmlReaderForFile(full_path.c_str(), NULL, 0);
00200   if (!reader) {
00201     xmlCleanupParser();
00202     return false;
00203   }
00204 
00205   bool ret;
00206   do {
00207     xml_t xml;
00208     ret = readXMLLine(xml, reader);
00209     if ((xml.depth != 1) || ((xml.type != XML_READER_TYPE_ELEMENT) &&
00210                              (xml.type != XML_READER_TYPE_TEXT))) {
00211       continue;
00212     }
00213     if (!xmlStrcmp(BAD_CAST "sys", xml.tag)) {
00214       // システム情報の読み出し
00215       readSysInfo(reader);
00216 
00217     } else if (!xmlStrcmp(BAD_CAST "users", xml.tag)) {
00218       // ユーザ情報の読み出し
00219       readAllUserInfo(reader);
00220     }
00221   } while (ret);
00222   setUserIndex(selected_index);
00223   xmlFreeTextReader(reader);
00224   xmlCleanupParser();
00225 
00226   loaded_file = full_path;
00227   if (users.empty()) {
00228     addUser();
00229   }
00230   return true;
00231 }
00232 
00233 
00234 bool Property::save(const char* file) {
00235   std::string save_file = (file) ? file : loaded_file;
00236   if (!save_file[0]) {
00237     return false;
00238   }
00239 
00240   // XML での書き出し
00241   xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
00242   xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "nettypingrc");
00243   xmlDocSetRootElement(doc, root_node);
00244 
00245   // システム情報の書き出し  
00246   xmlNodePtr node = xmlNewChild(root_node, NULL, BAD_CAST "sys", NULL);
00247   xmlNewChild(node, NULL, BAD_CAST "fullscreen",
00248               sys.fullscreen ? BAD_CAST "true" : BAD_CAST "false");
00249   char num_str[] = "0";
00250   num_str[0] += sys.user_index;
00251   xmlNewChild(node, NULL, BAD_CAST "user_index", BAD_CAST num_str);
00252 
00253   // ユーザ情報の書き出し
00254   xmlNodePtr user_node = xmlNewChild(root_node, NULL, BAD_CAST "users", NULL);
00255   for (std::vector<userInfo_t>::iterator it = users.begin();
00256        it != users.end(); ++it) {
00257     // 名前
00258     node = xmlNewChild(user_node, NULL, BAD_CAST "user", NULL);
00259     xmlNewChild(node, NULL, BAD_CAST "name", BAD_CAST it->name.c_str());
00260 
00261     // 出題数
00262     char nth[13];
00263     sprintf(nth, "%d", it->practice_num);
00264     xmlNewChild(node, NULL, BAD_CAST "practice_num", BAD_CAST nth);
00265 
00266     // 変更モード
00267     xmlNewChild(node, NULL, BAD_CAST "roman_convert",
00268                 it->roman_convert ? BAD_CAST "true" : BAD_CAST "false");
00269 
00270     // 自動改ページ
00271     xmlNewChild(node, NULL, BAD_CAST "auto_next",
00272                 it->auto_next ? BAD_CAST "true" : BAD_CAST "false");
00273 
00274     // 覚えようモード
00275     xmlNewChild(node, NULL, BAD_CAST "learn_mode",
00276                 it->learn_mode ? BAD_CAST "true" : BAD_CAST "false");
00277 
00278     // ランキング登録
00279     xmlNewChild(node, NULL, BAD_CAST "send_ranking",
00280                 it->send_ranking ? BAD_CAST "true" : BAD_CAST "false");
00281 
00282     // 登録先
00283     xmlNewChild(node, NULL, BAD_CAST "rank_page",
00284                 BAD_CAST it->rank_page.c_str());
00285   }
00286   int ret = xmlSaveFormatFileEnc(save_file.c_str(), doc, "UTF-8", 1);
00287   xmlFreeDoc(doc);
00288   xmlCleanupParser();
00289 
00290   return (ret < 0 ? false : true);
00291 }
00292 

Generated on Mon Apr 13 22:52:03 2009 by  doxygen 1.5.7.1