]> git.sur5r.net Git - openldap/blobdiff - contrib/ldapc++/src/LdifReader.cpp
Merge remote-tracking branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_5
[openldap] / contrib / ldapc++ / src / LdifReader.cpp
index 171378c2b6bba9d41e56b71a3a4dbb100e9ccee9..9db51e83411f93e70931a79792cfaad1eef911e6 100644 (file)
@@ -1,5 +1,6 @@
+// $OpenLDAP$
 /*
- * Copyright 2008, OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 2008-2013 The OpenLDAP Foundation, All Rights Reserved.
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 
 
 #include <string>
 #include <sstream>
+#include <stdexcept>
 
 #include <sasl/saslutil.h> // For base64 routines
 
 typedef std::pair<std::string, std::string> stringpair;
-LdifReader::LdifReader( std::istream &input ) : m_ldifstream(input)
+
+LdifReader::LdifReader( std::istream &input ) 
+        : m_ldifstream(input), m_lineNumber(0)
 {
     DEBUG(LDAP_DEBUG_TRACE, "<> LdifReader::LdifReader()" << std::endl);
     this->m_version = 0;
     // read the first record to find out version and type of the LDIF
-    if ( this->readNextRecord(true) )
-    {
-        this->m_currentIsFirst = true;
-    }
+    this->readNextRecord(true);
+    this->m_currentIsFirst = true;
 }
 
 int LdifReader::readNextRecord( bool first )
@@ -60,12 +62,9 @@ int LdifReader::readNextRecord( bool first )
             // End of Entry
             break;
         }
-        int rc = this->splitLine(line, type, value);
-        if ( rc )
-        {
-            DEBUG(LDAP_DEBUG_TRACE, " Error while splitting ldif line" 
-                    << std::endl);
-        }
+
+        this->splitLine(line, type, value);
+
         if ( numLine == 0 )
         {
             if ( type == "version" )
@@ -74,7 +73,10 @@ int LdifReader::readNextRecord( bool first )
                 valuestream >> this->m_version;
                 if ( this->m_version != 1 ) // there is no other Version than LDIFv1 
                 {
-                    //throw LdifException();
+                    std::ostringstream err;
+                    err << "Line " << this->m_lineNumber 
+                        << ": Unsuported LDIF Version";
+                    throw( std::runtime_error(err.str()) );
                 }
                 continue;
             }
@@ -87,16 +89,27 @@ int LdifReader::readNextRecord( bool first )
                 DEBUG(LDAP_DEBUG_TRACE, " Include directive: " << value << std::endl);
                 if ( this->m_version == 1 )
                 {
-                    // "include" is not an LDIFv1 feature
+                    std::ostringstream err;
+                    err << "Line " << this->m_lineNumber 
+                        << ": \"include\" not allowed in LDIF version 1.";
+                    throw( std::runtime_error(err.str()) );
+                }
+                else
+                {
+                    std::ostringstream err;
+                    err << "Line " << this->m_lineNumber 
+                        << ": \"include\" not yet suppported.";
+                    throw( std::runtime_error(err.str()) );
                 }
-                //this->readIncludeLine(value);
-                return 0;
             }
             else
             {
                 DEBUG(LDAP_DEBUG_TRACE, " Record doesn't start with a DN" 
                             << std::endl);
-                return 0;
+                std::ostringstream err;
+                err << "Line " << this->m_lineNumber 
+                    << ": LDIF record does not start with a DN.";
+                throw( std::runtime_error(err.str()) );
             }
         }
         if ( numLine == 1 ) // might contain "changtype" to indicate a change request
@@ -110,6 +123,10 @@ int LdifReader::readNextRecord( bool first )
                 else if (! this->m_ldifTypeRequest )
                 {
                     // Change Request in Entry record LDIF, should we accept it?
+                    std::ostringstream err;
+                    err << "Line " << this->m_lineNumber 
+                        << ": Change Request in an entry-only LDIF.";
+                    throw( std::runtime_error(err.str()) );
                 }
                 if ( value == "modify" )
                 {
@@ -131,7 +148,10 @@ int LdifReader::readNextRecord( bool first )
                 {
                     DEBUG(LDAP_DEBUG_TRACE, " Unknown change request <" 
                             << value << ">" << std::endl);
-                    return 0;
+                    std::ostringstream err;
+                    err << "Line " << this->m_lineNumber 
+                        << ": Unknown changetype: \"" << value << "\".";
+                    throw( std::runtime_error(err.str()) );
                 }
             }
             else
@@ -159,11 +179,12 @@ int LdifReader::readNextRecord( bool first )
 
 LDAPEntry LdifReader::getEntryRecord()
 {
+    std::list<stringpair>::const_iterator i = m_currentRecord.begin();
     if ( m_curRecType != LDAPMsg::SEARCH_ENTRY )
     {
-        // Error
+        throw( std::runtime_error( "The LDIF record: '" + i->second +
+                                   "' is not a valid LDAP Entry" ));
     }
-    std::list<stringpair>::const_iterator i = m_currentRecord.begin();
     LDAPEntry resEntry(i->second);
     i++;
     LDAPAttribute curAttr(i->first);
@@ -176,9 +197,14 @@ LDAPEntry LdifReader::getEntryRecord()
         }
         else
         {
-            if ( curAl->getAttributeByName( i->first ) )
+            const LDAPAttribute* existing = curAl->getAttributeByName( i->first );
+            if ( existing )
             {
-                // Attribute exists already -> Syntax Error
+                // Attribute exists already (handle gracefully)
+                curAl->addAttribute( curAttr );
+                curAttr = LDAPAttribute( *existing );
+                curAttr.addValue(i->second);
+                curAl->delAttribute( i->first );
             }
             else
             {
@@ -196,11 +222,11 @@ int LdifReader::getLdifLine(std::string &ldifline)
 {
     DEBUG(LDAP_DEBUG_TRACE, "-> LdifReader::getLdifLine()" << std::endl);
 
+    this->m_lineNumber++;
     if ( ! getline(m_ldifstream, ldifline) )
     {
         return -1;
     }
-
     while ( m_ldifstream &&
         (m_ldifstream.peek() == ' ' || m_ldifstream.peek() == '\t'))
     {
@@ -208,36 +234,43 @@ int LdifReader::getLdifLine(std::string &ldifline)
         m_ldifstream.ignore();
         getline(m_ldifstream, cat);
         ldifline += cat;
+        this->m_lineNumber++;
     }
 
     DEBUG(LDAP_DEBUG_TRACE, "<- LdifReader::getLdifLine()" << std::endl);
     return 0;
 }
 
-int LdifReader::splitLine(const std::string& line, 
+void LdifReader::splitLine(
+            const std::string& line, 
             std::string &type,
-            std::string &value)
+            std::string &value) const
 {
     std::string::size_type pos = line.find(':');
     if ( pos == std::string::npos )
     {
-        DEBUG(LDAP_DEBUG_ANY, "Invalid LDIF line. Not `:` separator" 
+        DEBUG(LDAP_DEBUG_ANY, "Invalid LDIF line. No `:` separator" 
                 << std::endl );
-        return -1;
+        std::ostringstream err;
+        err << "Line " << this->m_lineNumber << ": Invalid LDIF line. No `:` separator";
+        throw( std::runtime_error( err.str() ));
     }
+
     type = line.substr(0, pos);
     if ( pos == line.size() )
     {
         // empty value
         value = "";
-        return 0;
+        return;
     }
+
     pos++;
     char delim = line[pos];
     if ( delim == ':' || delim == '<' )
     {
         pos++;
     }
+
     for( ; pos < line.size() && isspace(line[pos]); pos++ )
     { /* empty */ }
 
@@ -258,21 +291,29 @@ int LdifReader::splitLine(const std::string& line,
         {
             value = "";
             DEBUG( LDAP_DEBUG_TRACE, " invalid base64 content" << std::endl );
-            return -1;
+            std::ostringstream err;
+            err << "Line " << this->m_lineNumber << ": Can't decode Base64 data";
+            throw( std::runtime_error( err.str() ));
         }
         else if ( rc == SASL_BUFOVER )
         {
             value = "";
             DEBUG( LDAP_DEBUG_TRACE, " not enough space in output buffer" 
                     << std::endl );
-            return -1;
+            std::ostringstream err;
+            err << "Line " << this->m_lineNumber 
+                << ": Can't decode Base64 data. Buffer too small";
+            throw( std::runtime_error( err.str() ));
         }
     }
     else if ( delim == '<' )
     {
         // URL value
         DEBUG(LDAP_DEBUG_TRACE, "  url value" << std::endl );
-        return -1;
+        std::ostringstream err;
+        err << "Line " << this->m_lineNumber 
+            << ": URLs are currently not supported";
+        throw( std::runtime_error( err.str() ));
     }
     else 
     {
@@ -281,7 +322,7 @@ int LdifReader::splitLine(const std::string& line,
     }
     DEBUG(LDAP_DEBUG_TRACE, "  Type: <" << type << ">" << std::endl );
     DEBUG(LDAP_DEBUG_TRACE, "  Value: <" << value << ">" << std::endl );
-    return 0;
+    return;
 }
 
 std::string LdifReader::readIncludeLine( const std::string& line ) const