PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/strigi-0.7.7/libstreamanalyzer/lib/fieldpropertiesdb.cpp

#
C++ | 817 lines | 672 code | 55 blank | 90 comment | 199 complexity | 7cdba6526123c16260ff4ae9ce817d2e MD5 | raw file
Possible License(s): LGPL-2.0
  1. /* This file is part of Strigi Desktop Search
  2. *
  3. * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
  4. * Copyright (C) 2007 Alexandr Goncearenco <neksa@neksa.net>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Library General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Library General Public License
  17. * along with this library; see the file COPYING.LIB. If not, write to
  18. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. * Boston, MA 02110-1301, USA.
  20. */
  21. #include <strigi/fieldpropertiesdb.h>
  22. #include "fieldproperties_private.h"
  23. #include <strigi/fieldtypes.h>
  24. #include <vector>
  25. #include <map>
  26. #include <iostream>
  27. #include <iterator>
  28. #include <set>
  29. #include <cstdlib>
  30. #include <cstring>
  31. #include <sys/types.h>
  32. #ifdef HAVE_DIRENT_H
  33. #include <dirent.h>
  34. #else
  35. #include "stgdirent.h"
  36. #endif
  37. #ifdef HAVE_STRINGS_H
  38. #include <strings.h>
  39. #endif
  40. #include <libxml/SAX2.h>
  41. #include <sys/stat.h>
  42. #include <config.h>
  43. #ifdef _MSC_VER
  44. # define strcasecmp stricmp
  45. #endif
  46. using namespace Strigi;
  47. using namespace std;
  48. class FieldPropertiesDb::Private {
  49. public:
  50. map<string, FieldProperties> properties;
  51. map<string, FieldProperties> propertiesByAlias;
  52. map<string, ClassProperties> classes;
  53. static const FieldProperties& emptyField();
  54. static const ClassProperties& emptyClass();
  55. Private();
  56. static vector<string> getdirs(const string&);
  57. static vector<string> getXdgDirs();
  58. void addEssentialProperties();
  59. void loadProperties(const string& dir);
  60. void parseProperties(FILE* f);
  61. void storeProperties(FieldProperties::Private& props);
  62. void warnIfLocale(const char* name, size_t len, const string& locale);
  63. // SAX Callbacks and stuff
  64. map<string, FieldProperties::Private> pProperties;
  65. map<string, ClassProperties::Private> pClasses;
  66. bool saxError;
  67. enum {defNone, defClass, defProperty} currentDefinition;
  68. string currentSubElement;
  69. string currentElementChars;
  70. string currentElementLang;
  71. string currentElementResource;
  72. bool nestedResource;
  73. FieldProperties::Private currentField;
  74. ClassProperties::Private currentClass;
  75. map<string, xmlEntity> xmlEntities;
  76. void setDefinitionAttribute(const char* name, size_t namelen,
  77. const char * value, size_t valuelen);
  78. static void charactersSAXFunc(void* ctx, const xmlChar * ch, int len);
  79. static void errorSAXFunc(void* ctx, const char * msg, ...);
  80. static void startElementNsSAX2Func(void * ctx,
  81. const xmlChar* localname, const xmlChar* prefix, const xmlChar* URI,
  82. int nb_namespaces, const xmlChar ** namespaces, int nb_attributes,
  83. int nb_defaulted, const xmlChar ** attributes);
  84. static void endElementNsSAX2Func(void *ctx,
  85. const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI);
  86. static xmlEntityPtr getEntitySAXFunc(void * ctx, const xmlChar * name);
  87. static void xmlSAX2EntityDecl(void * ctx, const xmlChar * name, int type,
  88. const xmlChar * publicId, const xmlChar * systemId, xmlChar * content);
  89. static bool isBoolValid(const char *uri, const char* name,
  90. const char* value, bool& result);
  91. };
  92. const FieldProperties&
  93. FieldPropertiesDb::Private::emptyField() {
  94. static const FieldProperties e;
  95. return e;
  96. }
  97. const ClassProperties&
  98. FieldPropertiesDb::Private::emptyClass() {
  99. static const ClassProperties f;
  100. return f;
  101. }
  102. FieldPropertiesDb&
  103. FieldPropertiesDb::db() {
  104. static FieldPropertiesDb db;
  105. return db;
  106. }
  107. FieldPropertiesDb::FieldPropertiesDb() :p(new Private()) {
  108. }
  109. FieldPropertiesDb::~FieldPropertiesDb() {
  110. delete p;
  111. }
  112. const FieldProperties&
  113. FieldPropertiesDb::properties(const std::string& uri) const {
  114. map<std::string, FieldProperties>::const_iterator j
  115. = p->properties.find(uri);
  116. if (j == p->properties.end()) {
  117. return FieldPropertiesDb::Private::emptyField();
  118. } else {
  119. return j->second;
  120. }
  121. }
  122. const FieldProperties&
  123. FieldPropertiesDb::propertiesByAlias(const std::string& alias) const {
  124. map<std::string, FieldProperties>::const_iterator j
  125. = p->propertiesByAlias.find(alias);
  126. if (j == p->propertiesByAlias.end()) {
  127. return FieldPropertiesDb::Private::emptyField();
  128. } else {
  129. return j->second;
  130. }
  131. }
  132. const map<string, FieldProperties>&
  133. FieldPropertiesDb::allProperties() const {
  134. return p->properties;
  135. }
  136. const ClassProperties&
  137. FieldPropertiesDb::classes(const std::string& uri) const {
  138. map<std::string, ClassProperties>::const_iterator j = p->classes.find(uri);
  139. if (j == p->classes.end()) {
  140. return FieldPropertiesDb::Private::emptyClass();
  141. } else {
  142. return j->second;
  143. }
  144. }
  145. const map<string, ClassProperties>&
  146. FieldPropertiesDb::allClasses() const {
  147. return p->classes;
  148. }
  149. vector<string>
  150. FieldPropertiesDb::Private::getdirs(const string& direnv) {
  151. vector<string> dirs;
  152. string::size_type lastp = 0;
  153. string::size_type p = direnv.find(':');
  154. while (p != string::npos) {
  155. dirs.push_back(direnv.substr(lastp, p-lastp));
  156. lastp = p+1;
  157. p = direnv.find(':', lastp);
  158. }
  159. dirs.push_back(direnv.substr(lastp));
  160. return dirs;
  161. }
  162. vector<string>
  163. FieldPropertiesDb::Private::getXdgDirs() {
  164. // find the XDG HOME directories or if not defined the local HOME dirs
  165. vector<string> dirs;
  166. const char* dirpath = getenv("XDG_DATA_HOME");
  167. if (dirpath) {
  168. dirs = getdirs(dirpath);
  169. } else {
  170. dirpath = getenv("HOME");
  171. if (dirpath) {
  172. dirs = getdirs(string(dirpath)+"/.local/share");
  173. }
  174. }
  175. // add the XDG DATA directories or if not defined the default dirs
  176. dirpath = getenv("XDG_DATA_DIRS");
  177. vector<string> d;
  178. if (dirpath) {
  179. d = getdirs(dirpath);
  180. } else {
  181. d = getdirs(INSTALLDIR "/share:/usr/local/share:/usr/share");
  182. }
  183. copy(d.begin(), d.end(), back_insert_iterator<vector<string> >(dirs));
  184. return dirs;
  185. }
  186. FieldPropertiesDb::Private::Private() {
  187. // some properties are defined hard in the code because they are essential
  188. addEssentialProperties();
  189. vector<string> dirs = getXdgDirs();
  190. vector<string>::const_iterator i;
  191. set<string> done;
  192. for (i=dirs.begin(); i!=dirs.end(); ++i) {
  193. if (done.find(*i) == done.end()) {
  194. done.insert(*i);
  195. loadProperties(*i);
  196. }
  197. }
  198. // Generate childUris, applicable* and locales values.
  199. for (map<string, FieldProperties::Private>::const_iterator prop
  200. = pProperties.begin();
  201. prop != pProperties.end(); ++prop) {
  202. FieldProperties::Private property = prop->second;
  203. for (map<string,FieldProperties::Localized>::iterator l
  204. = property.localized.begin();
  205. l != property.localized.end(); ++l) {
  206. property.locales.push_back(l->first);
  207. }
  208. const vector<string>& parents = property.parentUris;
  209. for (vector<string>::const_iterator parent = parents.begin();
  210. parent != parents.end(); ++parent ) {
  211. pProperties[*parent].childUris.push_back(property.uri);
  212. }
  213. const vector<string>& applicable = property.applicableClasses;
  214. for (vector<string>::const_iterator aclass = applicable.begin();
  215. aclass != applicable.end(); ++aclass ) {
  216. pClasses[*aclass].applicableProperties.push_back(property.uri);
  217. }
  218. }
  219. for (map<string, ClassProperties::Private>::const_iterator aclass
  220. = pClasses.begin();
  221. aclass != pClasses.end(); ++aclass) {
  222. ClassProperties::Private cclass = aclass->second;
  223. for (map<string,ClassProperties::Localized>::iterator l
  224. = cclass.localized.begin();
  225. l != cclass.localized.end(); ++l) {
  226. cclass.locales.push_back(l->first);
  227. }
  228. const vector<string>& parents = cclass.parentUris;
  229. for (vector<string>::const_iterator parent = parents.begin();
  230. parent != parents.end(); ++parent ) {
  231. pClasses[*parent].childUris.push_back(cclass.uri);
  232. }
  233. }
  234. copy(pClasses.begin(), pClasses.end(), inserter(classes, classes.end()) );
  235. // Construct properties and propertiesByAlias lists
  236. for (map<string, FieldProperties::Private>::const_iterator prop
  237. = pProperties.begin(); prop != pProperties.end(); ++prop) {
  238. FieldProperties property(prop->second);
  239. string alias = prop->second.alias;
  240. if(alias.size()) {
  241. if(propertiesByAlias.find(alias) == propertiesByAlias.end()) {
  242. propertiesByAlias[alias] = property;
  243. } else {
  244. //FIXME: use loging framework
  245. // cerr << "Error: alias " << alias << " requested by several properties: " << propertiesByAlias.find(alias)->second.uri()
  246. // << ", " << prop->second.uri
  247. // << endl;
  248. }
  249. }
  250. if (properties.find(property.uri()) == properties.end()) {
  251. properties[property.uri()] = property;
  252. }
  253. }
  254. pProperties.clear();
  255. pClasses.clear();
  256. }
  257. // FIXME (phreedom): should not directly fill properties[]
  258. // not all properties from fieldtypes.* are created
  259. void
  260. FieldPropertiesDb::Private::addEssentialProperties() {
  261. FieldProperties::Private props;
  262. props.stored = true;
  263. props.typeuri = FieldRegister::datetimeType;
  264. props.uri = FieldRegister::mtimeFieldName;
  265. properties[FieldRegister::mtimeFieldName] = props;
  266. props.typeuri = FieldRegister::integerType;
  267. props.uri = FieldRegister::sizeFieldName;
  268. properties[FieldRegister::sizeFieldName] = props;
  269. props.uri = FieldRegister::embeddepthFieldName;
  270. properties[FieldRegister::embeddepthFieldName] = props;
  271. props.typeuri = FieldRegister::stringType;
  272. props.uri = FieldRegister::pathFieldName;
  273. props.tokenized = false; // should not be tokenized: needed for retrieval
  274. properties[FieldRegister::pathFieldName] = props;
  275. props.uri = FieldRegister::filenameFieldName;
  276. props.tokenized = true;
  277. properties[FieldRegister::filenameFieldName] = props;
  278. props.uri = FieldRegister::mimetypeFieldName;
  279. properties[FieldRegister::mimetypeFieldName] = props;
  280. props.uri = FieldRegister::parentLocationFieldName;
  281. props.tokenized = false; // should not be tokenized: needed for retrieval
  282. properties[FieldRegister::parentLocationFieldName] = props;
  283. }
  284. void
  285. FieldPropertiesDb::Private::loadProperties(const string& dir) {
  286. string pdir = dir + "/strigi/fieldproperties/";
  287. DIR* d = opendir(pdir.c_str());
  288. if (!d) {
  289. pdir = dir;
  290. d = opendir(pdir.c_str());
  291. }
  292. if (!d) {
  293. return;
  294. }
  295. if (pdir[pdir.length()-1] != '/') {
  296. pdir.append("/");
  297. }
  298. struct dirent* de = readdir(d);
  299. struct stat s;
  300. while (de) {
  301. string path(pdir+de->d_name);
  302. if (path.length() >= 5 && path.compare(path.length() - 5, 5, ".rdfs", 5) == 0 &&
  303. !stat(path.c_str(), &s) && S_ISREG(s.st_mode)) {
  304. FILE* f = fopen(path.c_str(), "r");
  305. if (f) {
  306. parseProperties(f);
  307. fclose(f);
  308. }
  309. }
  310. de = readdir(d);
  311. }
  312. closedir(d);
  313. }
  314. namespace {
  315. int
  316. strigi_xmlFileRead(void* context, char* buffer, int len) {
  317. FILE* f = (FILE*)context;
  318. return (int)fread(buffer, 1, len, f);
  319. }
  320. int
  321. strigi_xmlFileClose(void*) {
  322. return 0;
  323. }
  324. }
  325. void
  326. FieldPropertiesDb::Private::parseProperties(FILE* f) {
  327. FieldProperties::Private props;
  328. xmlParserCtxtPtr ctxt;
  329. xmlSAXHandler handler;
  330. memset(&handler, 0, sizeof(xmlSAXHandler));
  331. handler.initialized = XML_SAX2_MAGIC;
  332. handler.characters = charactersSAXFunc;
  333. handler.error = errorSAXFunc;
  334. handler.startElementNs = startElementNsSAX2Func;
  335. handler.endElementNs = endElementNsSAX2Func;
  336. handler.getEntity = getEntitySAXFunc;
  337. handler.entityDecl = xmlSAX2EntityDecl;
  338. saxError = false;
  339. currentSubElement = "";
  340. currentElementChars = "";
  341. currentField.clear();
  342. currentClass.clear();
  343. currentDefinition = defNone;
  344. nestedResource = false;
  345. ctxt = xmlCreateIOParserCtxt(&handler, this, strigi_xmlFileRead, strigi_xmlFileClose, f, XML_CHAR_ENCODING_NONE);
  346. if (ctxt == 0) {
  347. saxError = true;
  348. } else {
  349. xmlCtxtUseOptions(ctxt, XML_PARSE_NOENT);
  350. if (xmlParseDocument(ctxt)) {
  351. saxError = true;
  352. }
  353. }
  354. if(saxError) {
  355. //FIXME: use logging framework
  356. // cerr << "saxError in FieldPropertiesDB::parseProperties." << endl;
  357. }
  358. xmlFreeDoc(ctxt->myDoc);
  359. xmlFreeParserCtxt(ctxt);
  360. for (map<std::string, xmlEntity>::iterator j=xmlEntities.begin();
  361. j!=xmlEntities.end(); ++j) {
  362. delete [] j->second.name;
  363. delete [] j->second.content;
  364. }
  365. xmlEntities.clear();
  366. }
  367. void
  368. FieldPropertiesDb::Private::xmlSAX2EntityDecl(void * ctx, const xmlChar * name,
  369. int type, const xmlChar* publicId, const xmlChar* systemId,
  370. xmlChar* content) {
  371. Private* p = (Private*)ctx;
  372. string stdname((const char*)name);
  373. map<std::string, xmlEntity>::const_iterator j
  374. = p->xmlEntities.find(stdname);
  375. if (j == p->xmlEntities.end()) {
  376. xmlEntity& newEntity = p->xmlEntities[stdname];
  377. newEntity.type = XML_ENTITY_DECL;
  378. newEntity.name = (xmlChar*)new char[stdname.size()+1];
  379. strcpy((char*)newEntity.name, stdname.c_str());
  380. newEntity.length = (int)strlen((const char*)content);
  381. newEntity.orig = (xmlChar*)new char[newEntity.length+1];
  382. strcpy((char*)newEntity.orig, (const char*)content);
  383. newEntity.content = newEntity.orig;
  384. newEntity.etype = XML_INTERNAL_GENERAL_ENTITY;
  385. newEntity.URI = newEntity.orig;
  386. } else {
  387. // FIXME: use logging framework
  388. // cerr << "Error: entity " << name << " redeclared." << endl;
  389. }
  390. }
  391. xmlEntityPtr
  392. FieldPropertiesDb::Private::getEntitySAXFunc(void * ctx, const xmlChar * name) {
  393. Private* p = (Private*)ctx;
  394. map<std::string, xmlEntity>::iterator j
  395. = p->xmlEntities.find((const char *)name);
  396. if (j == p->xmlEntities.end()) {
  397. return NULL;
  398. } else {
  399. return &j->second;
  400. }
  401. }
  402. void
  403. FieldPropertiesDb::Private::charactersSAXFunc(void* ctx, const xmlChar* ch,
  404. int len) {
  405. Private* p = (Private*)ctx;
  406. p->currentElementChars.append((const char *)ch, len);
  407. }
  408. void
  409. FieldPropertiesDb::Private::errorSAXFunc(void* ctx, const char* msg, ...) {
  410. Private* p = (Private*)ctx;
  411. p->saxError = true;
  412. string e;
  413. va_list args;
  414. va_start(args, msg);
  415. e += string(" ")+va_arg(args,char*);
  416. va_end(args);
  417. // FIXME: use logging framework
  418. // cerr << "Error: " << e << endl;
  419. }
  420. bool
  421. FieldPropertiesDb::Private::isBoolValid(const char *uri, const char* name,
  422. const char* value, bool& result){
  423. while (isspace(*value)) value++;
  424. if (strcasecmp(value,"false") == 0) {
  425. result = false;
  426. } else if (strcasecmp(value,"true") == 0) {
  427. result = true;
  428. } else {
  429. // FIXME: use logging framework
  430. // cerr << name << " flag value[" << value << "] for " << uri
  431. // << " is unrecognized. Should be in set {True,False}." << endl;
  432. return false;
  433. }
  434. return true;
  435. }
  436. namespace {
  437. // due to inlining, the strlen(B) is evaluated at runtime when B is a literal
  438. // string
  439. inline bool compare(const char* a, size_t alen, const char* b) {
  440. return alen == strlen(b) && strncmp(a, b, strlen(b)) == 0;
  441. }
  442. }
  443. void
  444. FieldPropertiesDb::Private::setDefinitionAttribute(const char* name,
  445. size_t namelen, const char* value, size_t valuelen) {
  446. bool boolValue;
  447. //Trim leading and trailing whitespace
  448. size_t numspaces = strspn(value, " \t\n\r");
  449. value += numspaces;
  450. valuelen -= numspaces;
  451. while (valuelen > 0 && strchr(" \t\n\r", value[valuelen-1])) {
  452. valuelen--;
  453. }
  454. if (currentDefinition == defProperty) {
  455. if (compare(name, namelen, "about")) {
  456. warnIfLocale(value, valuelen, currentElementLang);
  457. if (currentField.uri.size()) {
  458. // FIXME: use logging framework
  459. // cerr << "Uri is already defined for " << currentField.uri << "."
  460. // << endl;
  461. } else {
  462. currentField.uri.assign(value, valuelen);
  463. }
  464. } else if (compare(name, namelen, "alias")) {
  465. warnIfLocale(value, valuelen, currentElementLang);
  466. if (currentField.alias.size()) {
  467. // FIXME: use logging framework
  468. // cerr << "alias is already defined for " << currentField.uri << "."
  469. // << endl;
  470. } else {
  471. currentField.alias.assign(value, valuelen);
  472. }
  473. } else if (compare(name, namelen, "range")) {
  474. warnIfLocale(currentField.uri.c_str(), currentField.uri.size(), currentElementLang);
  475. if (currentField.typeuri.size()) {
  476. // FIXME: use logging framework
  477. // cerr << "range is already defined for " << currentField.uri
  478. // << "." << endl;
  479. } else {
  480. currentField.typeuri.assign(currentElementResource);
  481. }
  482. } else if (compare(name, namelen, "label")) {
  483. if (currentElementLang.size()) {
  484. FieldProperties::Localized l(
  485. currentField.localized[currentElementLang]);
  486. if (l.name.size()) {
  487. // FIXME: use logging framework
  488. // cerr << "label [" << currentElementLang
  489. // << "] is already defined for " << currentField.uri
  490. // << "." << endl;
  491. } else {
  492. l.name.assign(value, valuelen);
  493. currentField.localized[currentElementLang] = l;
  494. }
  495. } else if (currentField.name.size()) {
  496. // FIXME: use logging framework
  497. // cerr << "label is already defined for " << currentField.uri
  498. // << "." << endl;
  499. } else {
  500. currentField.name.assign(value, valuelen);
  501. }
  502. } else if (compare(name, namelen, "comment")) {
  503. if (currentElementLang.size()) {
  504. FieldProperties::Localized l(
  505. currentField.localized[currentElementLang]);
  506. if (l.description.size()) {
  507. // FIXME: use logging framework
  508. // cerr << "comment[" << currentElementLang
  509. // << "] is already defined for " << currentField.uri
  510. // << "." << endl;
  511. } else {
  512. l.description.assign(value, valuelen);
  513. currentField.localized[currentElementLang] = l;
  514. }
  515. } else if (currentField.description.size()) {
  516. // FIXME: use logging framework
  517. // cerr << "comment is already defined for " << currentField.uri
  518. // << "." << endl;
  519. } else {
  520. currentField.description.assign(value, valuelen);
  521. }
  522. } else if (compare(name, namelen, "subPropertyOf")) {
  523. currentField.parentUris.push_back(currentElementResource);
  524. } else if (compare(name, namelen, "domain")) {
  525. currentField.applicableClasses.push_back(currentElementResource);
  526. } else if (compare(name, namelen, "binary")) {
  527. if (isBoolValid(currentField.uri.c_str(), "binary", value,
  528. boolValue)) {
  529. currentField.binary = boolValue;
  530. }
  531. } else if (compare(name, namelen, "compressed")) {
  532. if (isBoolValid(currentField.uri.c_str(), "compressed", value,
  533. boolValue)) {
  534. currentField.compressed = boolValue;
  535. }
  536. } else if (compare(name, namelen, "indexed")) {
  537. if (isBoolValid(currentField.uri.c_str(), "indexed", value,
  538. boolValue)) {
  539. currentField.indexed = boolValue;
  540. }
  541. } else if (compare(name, namelen, "stored")) {
  542. if (isBoolValid(currentField.uri.c_str(), "stored", value,
  543. boolValue)) {
  544. currentField.stored = boolValue;
  545. }
  546. } else if (compare(name, namelen, "tokenized")) {
  547. if (isBoolValid(currentField.uri.c_str(), "tokenized", value,
  548. boolValue)) {
  549. currentField.tokenized = boolValue;
  550. }
  551. } else if (compare(name, namelen, "minCardinality")) {
  552. currentField.min_cardinality = atoi(value);
  553. } else if (compare(name, namelen, "maxCardinality")) {
  554. currentField.max_cardinality = atoi(value);
  555. }
  556. } else if (currentDefinition == defClass) {
  557. if (compare(name, namelen, "about")) {
  558. warnIfLocale(value, valuelen, currentElementLang);
  559. if (currentClass.uri.size()) {
  560. // FIXME: use logging framework
  561. // cerr << "Uri is already defined for " << currentClass.uri
  562. // << "." << endl;
  563. }
  564. } else {
  565. currentClass.uri.assign(value, valuelen);
  566. }
  567. } else if (compare(name, namelen, "label")) {
  568. if (currentElementLang.size()) {
  569. ClassProperties::Localized l(
  570. currentClass.localized[currentElementLang]);
  571. if (l.name.size()) {
  572. // FIXME: use logging framework
  573. // cerr << "label[" << currentElementLang
  574. // << "] is already defined for " << currentClass.uri
  575. // << "." << endl;
  576. } else {
  577. l.name.assign(value, valuelen);
  578. currentClass.localized[currentElementLang] = l;
  579. }
  580. } else if (currentClass.name.size()) {
  581. // FIXME: use logging framework
  582. // cerr << "label is already defined for " << currentClass.uri
  583. // << "." << endl;
  584. } else {
  585. currentClass.name.assign(value, valuelen);
  586. }
  587. } else if (compare(name, namelen, "comment")) {
  588. if (currentElementLang.size()) {
  589. ClassProperties::Localized l(
  590. currentClass.localized[currentElementLang]);
  591. if (l.description.size()) {
  592. // FIXME: use logging framework
  593. // cerr << "comment[" << currentElementLang
  594. // << "] is already defined for " << currentClass.uri
  595. // << "." << endl;
  596. } else {
  597. l.description.assign(value, valuelen);
  598. currentClass.localized[currentElementLang] = l;
  599. }
  600. } else if (currentField.description.size()) {
  601. // FIXME: use logging framework
  602. // cerr << "comment is already defined for " << currentClass.uri
  603. // << "." << endl;
  604. } else {
  605. currentClass.description.assign(value, valuelen);
  606. }
  607. } else if(compare(name, namelen, "subClassOf")) {
  608. currentClass.parentUris.push_back(currentElementResource);
  609. }
  610. }
  611. void
  612. FieldPropertiesDb::Private::startElementNsSAX2Func(void * ctx,
  613. const xmlChar* localname, const xmlChar* prefix, const xmlChar* URI,
  614. int nb_namespaces, const xmlChar ** namespaces, int nb_attributes,
  615. int nb_defaulted, const xmlChar ** attributes) {
  616. Private* p = (Private*)ctx;
  617. if (p->currentDefinition == defNone) {
  618. if (strcmp((const char *)localname, "Property") == 0) {
  619. p->currentDefinition = defProperty;
  620. } else if (strcmp((const char *)localname, "Class") == 0) {
  621. p->currentDefinition = defClass;
  622. }
  623. if (p->currentDefinition != defNone) {
  624. for (int i=0; i<nb_attributes; i++) {
  625. const xmlChar ** a = attributes + i*5;
  626. p->setDefinitionAttribute((const char*)a[0],
  627. strlen((const char*)a[0]), (const char*)a[3], a[4]-a[3]);
  628. }
  629. }
  630. } else {
  631. if ( (strcmp((const char *)localname, "Property") == 0) ||
  632. (strcmp((const char *)localname, "Class") == 0) ) {
  633. p->nestedResource = true;
  634. } else {
  635. p->currentSubElement = (const char *)localname;
  636. }
  637. for (int i=0; i<nb_attributes; i++) {
  638. const xmlChar ** a = attributes + i*5;
  639. size_t len = a[0]-a[1];
  640. if (len == 8 && strncmp((const char*)attributes[i*5], "resource", 8) == 0) {
  641. p->currentElementResource.assign((const char*)a[3], a[4]-a[3]);
  642. } else if (strcmp((const char*)attributes[i*5], "about") == 0) {
  643. p->currentElementResource.assign((const char*)a[3], a[4]-a[3]);
  644. } else if (strcmp((const char*)attributes[i*5], "lang") == 0) {
  645. p->currentElementLang.assign((const char*)a[3], a[4]-a[3]);
  646. }
  647. }
  648. }
  649. }
  650. void
  651. FieldPropertiesDb::Private::endElementNsSAX2Func(void *ctx,
  652. const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI) {
  653. Private *p = (Private *) ctx;
  654. if (p->currentDefinition!=defNone) {
  655. if (strcmp((const char *)localname, "Property") == 0) {
  656. if (p->nestedResource) {
  657. p->nestedResource = false;
  658. } else {
  659. if (p->currentField.uri.size()) {
  660. if(!p->currentField.alias.size()) {
  661. size_t pos;
  662. if ((pos = p->currentField.uri.rfind('#')) != string::npos){
  663. p->currentField.alias = p->currentField.uri.substr(pos+1);
  664. }
  665. }
  666. p->pProperties[p->currentField.uri] = p->currentField;
  667. p->currentField.clear();
  668. }
  669. p->currentDefinition = defNone;
  670. }
  671. } else if (strcmp((const char *)localname, "Class") == 0) {
  672. if (p->nestedResource) {
  673. p->nestedResource = false;
  674. } else {
  675. if (p->currentClass.uri.size()) {
  676. p->pClasses[p->currentClass.uri] = p->currentClass;
  677. p->currentClass.clear();
  678. }
  679. p->currentDefinition = defNone;
  680. }
  681. } else {
  682. if (p->currentSubElement == (const char*)localname) {
  683. p->setDefinitionAttribute(p->currentSubElement.c_str(),
  684. p->currentSubElement.size(),
  685. p->currentElementChars.c_str(),
  686. p->currentElementChars.size());
  687. p->currentSubElement = "";
  688. p->currentElementChars = "";
  689. p->currentElementResource = "";
  690. p->currentElementLang = "";
  691. } else {
  692. // FIXME: use logging framework
  693. // cerr << "ERROR: Wrong closing element " << localname
  694. // << "." << endl;
  695. }
  696. }
  697. }
  698. }
  699. void
  700. FieldPropertiesDb::Private::storeProperties(FieldProperties::Private& p) {
  701. if (p.uri.size()) {
  702. properties[p.uri] = p;
  703. }
  704. p.clear();
  705. }
  706. void
  707. FieldPropertiesDb::Private::warnIfLocale(const char* name, size_t len, const string& locale) {
  708. if (locale.size()) {
  709. // FIXME: use logging framework
  710. // cerr << "Warning: you cannot define a locale for the resource URI "
  711. // << name << "." << endl;
  712. }
  713. }
  714. void
  715. FieldPropertiesDb::addField(const std::string& key, const std::string& type,
  716. const std::string& parent) {
  717. FieldProperties::Private props;
  718. props.uri = key;
  719. props.typeuri = type;
  720. if (parent.size()) {
  721. props.parentUris.push_back(parent);
  722. }
  723. p->properties[key] = props;
  724. }
  725. void
  726. FieldPropertiesDb::addField(const std::string& key) {
  727. FieldProperties::Private props;
  728. props.uri = key;
  729. props.typeuri = FieldRegister::stringType;
  730. p->properties[key] = props;
  731. }
  732. void
  733. FieldProperties::Private::clear() {
  734. uri.clear();
  735. name.clear();
  736. alias.clear();
  737. description.clear();
  738. localized.clear();
  739. locales.clear();
  740. typeuri.clear();
  741. parentUris.clear();
  742. childUris.clear();
  743. applicableClasses.clear();
  744. indexed = true;
  745. stored = true;
  746. tokenized = true;
  747. compressed = false;
  748. binary = false;
  749. min_cardinality = 0;
  750. max_cardinality = -1; /** unlimited */
  751. }
  752. void
  753. ClassProperties::Private::clear() {
  754. uri.clear();
  755. name.clear();
  756. description.clear();
  757. localized.clear();
  758. locales.clear();
  759. parentUris.clear();
  760. childUris.clear();
  761. applicableProperties.clear();
  762. }