Back to index

nordugrid-arc-nox  1.1.0~rc6
LDIFtoXML.cpp
Go to the documentation of this file.
00001 #include <ctype.h>
00002 #include <arc/StringConv.h>
00003 
00004 #include "LDIFtoXML.h"
00005 
00006 namespace ARex {
00007 
00008 
00009 static bool get_ldif_string(std::istream& ldif,std::string& str) {
00010   while(ldif) {
00011     getline(ldif,str);
00012     if(str.empty()) continue;
00013     if(str[0] == '#') continue;
00014     return true;
00015   };
00016   return false;
00017 }
00018 
00019 static void strtolower(std::string& str) {
00020   std::string::size_type l = str.length();
00021   char* s = (char*)(str.c_str());
00022   for(;l>0;--l,++s) *s=tolower(*s);
00023 }
00024 
00025 static void trim(std::string& str) {
00026   std::string::size_type first = str.find_first_not_of(' ');
00027   if(first == std::string::npos) {
00028     str.resize(0); return;
00029   };
00030   std::string::size_type last = str.find_last_not_of(' ');
00031   str=str.substr(first,last-first+1);
00032   return;
00033 }
00034 
00035 static bool split_ldif_path(const std::string& str,std::list<std::pair<std::string,std::string> >& path) {
00036   std::string::size_type cur = 0;
00037   while(true) {
00038     std::string::size_type p = str.find('=',cur);
00039     if(p == std::string::npos) return true;
00040     std::string name = str.substr(cur,p-cur);
00041     std::string::size_type e = str.find(',',p);
00042     if(e == std::string::npos) e = str.length();
00043     std::string val = str.substr(p+1,e-p-1);
00044     trim(name); trim(val);
00045     strtolower(name); strtolower(val);
00046     path.push_front(std::pair<std::string,std::string>(name,val));
00047     cur=e+1;
00048   };
00049   return false;
00050 }
00051 
00052 static bool compare_paths(const std::list<std::pair<std::string,std::string> >& path1,const std::list<std::pair<std::string,std::string> >& path2,int size) {
00053   std::list<std::pair<std::string,std::string> >::const_iterator i1 = path1.begin();
00054   std::list<std::pair<std::string,std::string> >::const_iterator i2 = path2.begin();
00055   for(;size>0;--size) {
00056     if((i1 == path1.end()) && (i2 == path2.end())) break;
00057     if(i1 == path1.end()) return false;
00058     if(i2 == path2.end()) return false;
00059     if(i1->first != i2->first) return false;
00060     if(i1->second != i2->second) return false;
00061     ++i1; ++i2;
00062   };
00063   return true;
00064 }
00065 
00066 static Arc::XMLNode path_to_XML(const std::list<std::pair<std::string,std::string> >& path,Arc::XMLNode node) {
00067   Arc::XMLNode cur = node;
00068   std::list<std::pair<std::string,std::string> >::const_iterator i = path.begin();
00069   for(;i!=path.end();++i) {
00070     Arc::XMLNode n = cur[i->first];
00071     Arc::XMLNode nn;
00072     for(int num = 0;;++num) {
00073       nn=n[num];
00074       if(!nn) break;
00075       if((std::string)(nn.Attribute("name")) == i->second) break;
00076     };
00077     if(!nn) {
00078       nn=cur.NewChild(i->first);
00079       nn.NewAttribute("name")=i->second;
00080     };
00081     cur=nn;
00082   };
00083   return cur;  
00084 }
00085 
00086 static void reduce_name(std::string& name,Arc::XMLNode x) {
00087   std::string::size_type p = std::string::npos;
00088   for(;;) {
00089     p=name.rfind('-',p);
00090     if(p == std::string::npos) break;
00091     std::string urn = "urn:"+name.substr(0,p);
00092     std::string prefix = x.NamespacePrefix(urn.c_str());
00093     if(!prefix.empty()) {
00094       name=prefix+":"+name.substr(p+1);
00095       break;
00096     };
00097     --p;
00098   };
00099 }
00100 
00101 static void reduce_names(Arc::XMLNode x) {
00102   if(x.Size() == 0) return;
00103   std::string name = x.Name();
00104   reduce_name(name,x);
00105   x.Name(name.c_str());
00106   for(int n = 0;;++n) {
00107     Arc::XMLNode x_ = x.Child(n);
00108     if(!x_) break;
00109     reduce_names(x_);
00110   };
00111 }
00112 
00113 static void reduce_prefix(std::string& prefix) {
00114   std::string::size_type p = 0;
00115   p=0;
00116   for(;p<prefix.length();) {
00117     std::string::size_type p_ = p;
00118     for(;p_<prefix.length();++p_) if(prefix[p_] != '-') break;
00119     if(p!=p_) prefix.replace(p,p_-p,"");
00120     p_=prefix.find('-',p);
00121     if(p_ == std::string::npos) {
00122       prefix.replace(p+1,std::string::npos,"");
00123     } else {
00124       prefix.replace(p+1,p_-p,"");
00125     };
00126     ++p;
00127   };
00128 }
00129 
00130 bool LDIFtoXML(std::istream& ldif,const std::string& ldif_base,Arc::XMLNode xml) {
00131   std::list<std::pair<std::string,std::string> > base;
00132   split_ldif_path(ldif_base,base);
00133   std::string str;
00134   if(!get_ldif_string(ldif,str)) return true;
00135   for(;;) { // LDIF processing loop
00136     for(;;) { // Looking for dn:
00137       if(strncasecmp(str.c_str(),"dn:",3) == 0) break;
00138       if(!get_ldif_string(ldif,str)) { reduce_names(xml); return true; };
00139     };
00140     str.replace(0,3,"");
00141     std::list<std::pair<std::string,std::string> > dn;
00142     split_ldif_path(str,dn);
00143     if(base.size() > dn.size()) continue; // Above base
00144     if(!compare_paths(base,dn,base.size())) continue; // Wrong base
00145     // Removing base
00146     for(int n = 0;n<base.size();++n) dn.erase(dn.begin());
00147     Arc::XMLNode x = path_to_XML(dn,xml);
00148     if(!x) return false;
00149     Arc::NS ns;
00150     for(;;) { // Reading ObjectClass elements
00151       if(!get_ldif_string(ldif,str)) { reduce_names(xml); return true; };
00152       if(strncasecmp(str.c_str(),"objectclass:",12) != 0) break;
00153       // Converting ObjectClass into namespace
00154       str.replace(0,12,"");
00155       trim(str);
00156       std::string prefix=str;
00157       reduce_prefix(prefix);
00158       for(int n = 0;;++n) {
00159         if(ns.find(prefix+Arc::tostring(n)) == ns.end()) {
00160           ns[prefix+Arc::tostring(n)]="urn:"+str;
00161           break;
00162         };
00163       };
00164     };
00165     x.Namespaces(ns);
00166     // Read name:value data
00167     for(;;) {
00168       if(strncasecmp(str.c_str(),"dn:",3) == 0) break;
00169       std::string::size_type p = str.find(':');
00170       std::string name;
00171       std::string value;
00172       if(p == std::string::npos) {
00173         name=str;
00174       } else {
00175         name=str.substr(0,p);
00176         value=str.substr(p+1);
00177       };
00178       trim(name); trim(value);
00179       reduce_name(name,x);
00180       x.NewChild(name)=value; // TODO: XML escaping for value
00181       if(!get_ldif_string(ldif,str)) { reduce_names(xml); return true; };
00182     };
00183   };
00184   return false;
00185 }
00186 
00187 } // namespace ARex
00188