docs: @SuppressWarnings("checkstyle:magicnumber")
  	private List<DBaseFileField> extractColumns(List<? extends AttributeProvider> providers)
  			throws DBaseFileException, AttributeException {
  		final Map<String, DBaseFileField> attributeColumns = new TreeMap<>();
  		DBaseFileField oldField;
  		String name;
  		String kname;
  		int fieldSize;
  		int decimalSize;
  
  		final Set<String> skippedColumns = new TreeSet<>();
  
  		for (final AttributeProvider provider : providers) {
  			for (final Attribute attr : provider.attributes()) {
  				final DBaseFieldType dbftype = DBaseFieldType.fromAttributeType(attr.getType());
  				// The following types are not yet supported
  				if (isSupportedType(dbftype)) {
  					name = attr.getName();
  					kname = name.toLowerCase();
  					oldField = attributeColumns.get(kname);
  
  					// compute the sizes
  					fieldSize = computeFieldSize(attr);
  					decimalSize = computeDecimalSize(attr);
  
  					if (oldField == null) {
  						oldField = new DBaseFileField(
  								name,
  								dbftype,
  								fieldSize,
  								decimalSize);
  						attributeColumns.put(kname, oldField);
  					} else {
  						oldField.updateSizes(fieldSize, decimalSize);
  					}
  				} else {
  					skippedColumns.add(attr.getName().toUpperCase());
  				}
  			}
  
  			// Be sure that the memory was not fully filled by the saving process
  			provider.freeMemory();
  		}
  
  		//Max of field allowed : 128
  		if (attributeColumns.size() > 128) {
  			throw new TooManyDBaseColumnException(attributeColumns.size(), 128);
  		}
  
  		final List<DBaseFileField> dbColumns = new ArrayList<>();
  		dbColumns.addAll(attributeColumns.values());
  		attributeColumns.clear();
  
  		for (int idx = 0; idx < dbColumns.size(); ++idx) {
  			dbColumns.get(idx).setColumnIndex(idx);
  		}
  
  		if (!skippedColumns.isEmpty()) {
  			columnsSkipped(skippedColumns);
  		}
  
  		return dbColumns;
  	}