/**
  * Find the next Multipart Delimiter
  *
  * @param delimiter delimiter to find
  * @param dispositionStatus the next status if the delimiter is a start
  * @param closeDelimiterStatus the next status if the delimiter is a close delimiter
  * @return the next InterfaceHttpData if any
  * @throws ErrorDataDecoderException
  */
 private InterfaceHttpData findMultipartDelimiter(
     String delimiter, MultiPartStatus dispositionStatus, MultiPartStatus closeDelimiterStatus)
     throws ErrorDataDecoderException {
   // --AaB03x or --AaB03x--
   int readerIndex = undecodedChunk.readerIndex();
   HttpPostBodyUtil.skipControlCharacters(undecodedChunk);
   skipOneLine();
   String newline;
   try {
     newline = readLine();
   } catch (NotEnoughDataDecoderException e) {
     undecodedChunk.readerIndex(readerIndex);
     return null;
   }
   if (newline.equals(delimiter)) {
     currentStatus = dispositionStatus;
     return decodeMultipart(dispositionStatus);
   } else if (newline.equals(delimiter + "--")) {
     // CLOSEDELIMITER or MIXED CLOSEDELIMITER found
     currentStatus = closeDelimiterStatus;
     if (currentStatus == MultiPartStatus.HEADERDELIMITER) {
       // MIXEDCLOSEDELIMITER
       // end of the Mixed part
       currentFieldAttributes = null;
       return decodeMultipart(MultiPartStatus.HEADERDELIMITER);
     }
     return null;
   }
   undecodedChunk.readerIndex(readerIndex);
   throw new ErrorDataDecoderException("No Multipart delimiter found");
 }
 /**
  * Find the next Disposition
  *
  * @return the next InterfaceHttpData if any
  * @throws ErrorDataDecoderException
  */
 private InterfaceHttpData findMultipartDisposition() throws ErrorDataDecoderException {
   int readerIndex = undecodedChunk.readerIndex();
   if (currentStatus == MultiPartStatus.DISPOSITION) {
     currentFieldAttributes = new TreeMap<String, Attribute>(CaseIgnoringComparator.INSTANCE);
   }
   // read many lines until empty line with newline found! Store all data
   while (!skipOneLine()) {
     HttpPostBodyUtil.skipControlCharacters(undecodedChunk);
     String newline;
     try {
       newline = readLine();
     } catch (NotEnoughDataDecoderException e) {
       undecodedChunk.readerIndex(readerIndex);
       return null;
     }
     String[] contents = splitMultipartHeader(newline);
     if (contents[0].equalsIgnoreCase(HttpPostBodyUtil.CONTENT_DISPOSITION)) {
       boolean checkSecondArg = false;
       if (currentStatus == MultiPartStatus.DISPOSITION) {
         checkSecondArg = contents[1].equalsIgnoreCase(HttpPostBodyUtil.FORM_DATA);
       } else {
         checkSecondArg =
             contents[1].equalsIgnoreCase(HttpPostBodyUtil.ATTACHMENT)
                 || contents[1].equalsIgnoreCase(HttpPostBodyUtil.FILE);
       }
       if (checkSecondArg) {
         // read next values and store them in the map as Attribute
         for (int i = 2; i < contents.length; i++) {
           String[] values = contents[i].split("=");
           Attribute attribute;
           try {
             attribute =
                 factory.createAttribute(
                     request, values[0].trim(), decodeAttribute(cleanString(values[1]), charset));
           } catch (NullPointerException e) {
             throw new ErrorDataDecoderException(e);
           } catch (IllegalArgumentException e) {
             throw new ErrorDataDecoderException(e);
           }
           currentFieldAttributes.put(attribute.getName(), attribute);
         }
       }
     } else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING)) {
       Attribute attribute;
       try {
         attribute =
             factory.createAttribute(
                 request, HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, cleanString(contents[1]));
       } catch (NullPointerException e) {
         throw new ErrorDataDecoderException(e);
       } catch (IllegalArgumentException e) {
         throw new ErrorDataDecoderException(e);
       }
       currentFieldAttributes.put(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, attribute);
     } else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH)) {
       Attribute attribute;
       try {
         attribute =
             factory.createAttribute(
                 request, HttpHeaders.Names.CONTENT_LENGTH, cleanString(contents[1]));
       } catch (NullPointerException e) {
         throw new ErrorDataDecoderException(e);
       } catch (IllegalArgumentException e) {
         throw new ErrorDataDecoderException(e);
       }
       currentFieldAttributes.put(HttpHeaders.Names.CONTENT_LENGTH, attribute);
     } else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_TYPE)) {
       // Take care of possible "multipart/mixed"
       if (contents[1].equalsIgnoreCase(HttpPostBodyUtil.MULTIPART_MIXED)) {
         if (currentStatus == MultiPartStatus.DISPOSITION) {
           String[] values = contents[2].split("=");
           multipartMixedBoundary = "--" + values[1];
           currentStatus = MultiPartStatus.MIXEDDELIMITER;
           return decodeMultipart(MultiPartStatus.MIXEDDELIMITER);
         } else {
           throw new ErrorDataDecoderException(
               "Mixed Multipart found in a previous Mixed Multipart");
         }
       } else {
         for (int i = 1; i < contents.length; i++) {
           if (contents[i].toLowerCase().startsWith(HttpHeaders.Values.CHARSET)) {
             String[] values = contents[i].split("=");
             Attribute attribute;
             try {
               attribute =
                   factory.createAttribute(
                       request, HttpHeaders.Values.CHARSET, cleanString(values[1]));
             } catch (NullPointerException e) {
               throw new ErrorDataDecoderException(e);
             } catch (IllegalArgumentException e) {
               throw new ErrorDataDecoderException(e);
             }
             currentFieldAttributes.put(HttpHeaders.Values.CHARSET, attribute);
           } else {
             Attribute attribute;
             try {
               attribute =
                   factory.createAttribute(
                       request,
                       contents[0].trim(),
                       decodeAttribute(cleanString(contents[i]), charset));
             } catch (NullPointerException e) {
               throw new ErrorDataDecoderException(e);
             } catch (IllegalArgumentException e) {
               throw new ErrorDataDecoderException(e);
             }
             currentFieldAttributes.put(attribute.getName(), attribute);
           }
         }
       }
     } else {
       throw new ErrorDataDecoderException("Unknown Params: " + newline);
     }
   }
   // Is it a FileUpload
   Attribute filenameAttribute = currentFieldAttributes.get(HttpPostBodyUtil.FILENAME);
   if (currentStatus == MultiPartStatus.DISPOSITION) {
     if (filenameAttribute != null) {
       // FileUpload
       currentStatus = MultiPartStatus.FILEUPLOAD;
       // do not change the buffer position
       return decodeMultipart(MultiPartStatus.FILEUPLOAD);
     } else {
       // Field
       currentStatus = MultiPartStatus.FIELD;
       // do not change the buffer position
       return decodeMultipart(MultiPartStatus.FIELD);
     }
   } else {
     if (filenameAttribute != null) {
       // FileUpload
       currentStatus = MultiPartStatus.MIXEDFILEUPLOAD;
       // do not change the buffer position
       return decodeMultipart(MultiPartStatus.MIXEDFILEUPLOAD);
     } else {
       // Field is not supported in MIXED mode
       throw new ErrorDataDecoderException("Filename not found");
     }
   }
 }