private function _map_data($save_cols)
    {
        // flatten composite fields first
        foreach ($this->coltypes as $col => $colprop) {
            if (is_array($colprop['childs']) && ($values = $this->get_col_values($col, $save_cols, false))) {
                foreach ($values as $subtype => $childs) {
                    $subtype = $subtype ? ':'.$subtype : '';
                    foreach ($childs as $i => $child_values) {
                        foreach ((array)$child_values as $childcol => $value) {
                            $save_cols[$childcol.$subtype][$i] = $value;
                        }
                    }
                }
            }

            // if addresses are to be saved as serialized string, do so
            if (is_array($colprop['serialized'])) {
               foreach ($colprop['serialized'] as $subtype => $delim) {
                  $key = $col.':'.$subtype;
                  foreach ((array)$save_cols[$key] as $i => $val) {
                     $values = array($val['street'], $val['locality'], $val['zipcode'], $val['country']);
                     $save_cols[$key][$i] = count(array_filter($values)) ? join($delim, $values) : null;
                 }
               }
            }
        }

        $ldap_data = array();
        foreach ($this->fieldmap as $rf => $fld) {
            $val = $save_cols[$rf];

            // check for value in base field (eg.g email instead of email:foo)
            list($col, $subtype) = explode(':', $rf);
            if (!$val && !empty($save_cols[$col])) {
                $val = $save_cols[$col];
                unset($save_cols[$col]);  // only use this value once
            }
            else if (!$val && !$subtype) { // extract values from subtype cols
                $val = $this->get_col_values($col, $save_cols, true);
            }

            if (is_array($val))
                $val = array_filter($val);  // remove empty entries
            if ($fld && $val) {
                // The field does exist, add it to the entry.
                $ldap_data[$fld] = $val;
            }
        }

        foreach ($this->formats as $fld => $format) {
            if (empty($ldap_data[$fld])) {
                continue;
            }

            switch ($format['type']) {
            case 'date':
                if ($dt = rcube_utils::anytodatetime($ldap_data[$fld])) {
                    $ldap_data[$fld] = $dt->format($format['format']);
                }
                break;
            }
        }

        return $ldap_data;
    }