CSVResult sniff(Reader r) throws IOException {
            boolean eof = false;
            boolean hitMarkLimit = false;
            int lastC = -1;
            StringBuilder unquoted = new StringBuilder();
            try (PushbackReader reader = new PushbackReader(new CloseShieldReader(r), PUSH_BACK)) {
                int c = read(reader);
                while (c != EOF) {
                    if (c == quoteCharacter) {
                        handleUnquoted(unquoted);
                        //test to make sure there isn't an unencapsulated quote character
                        // in the middle of a cell
                        if (lastC > -1 && lastC != delimiter && lastC != NEW_LINE &&
                                lastC != CARRIAGE_RETURN) {
                            parseException = true;
                            return calcResult();
                        }
                        //TODO: test to make sure cell doesn't start with escaped
                        // ""the quick brown cat"
                        boolean correctlyEncapsulated = consumeQuoted(reader, quoteCharacter);
                        if (!correctlyEncapsulated) {
                            parseException = true;
                            return calcResult();
                        }
                    } else if (c == delimiter) {
                        handleUnquoted(unquoted);
                        endColumn();
                        consumeSpaceCharacters(reader);
                    } else if (c == NEW_LINE || c == CARRIAGE_RETURN) {
                        if (unquoted.length() > 0) {
                            endColumn();
                        }
                        handleUnquoted(unquoted);
                        endRow();
                        consumeNewLines(reader);
                    } else {
                        unquoted.append((char) c);
                    }
                    lastC = c;
                    c = read(reader);
                }
            } catch (HitMarkLimitException e) {
                hitMarkLimit = true;
            } catch (UnsurprisingEOF e) {
                //totally ignore
            } catch (EOFException e) {
                //the consume* throw this to avoid
                //having to check -1 every time and
                //having to rely on potentially wonky
                //inputstreams not consistently returning -1
                //after hitting EOF and returning the first -1.
                //Yes.  That's a thing.
                eof = true;
            } finally {
                r.reset();
            }
            //if you've hit the marklimit or an eof on a truncated file
            //don't add the last row's info
            if (!hitMarkLimit && !eof && lastC != NEW_LINE && lastC != CARRIAGE_RETURN) {
                handleUnquoted(unquoted);
                endColumn();
                endRow();
            }
            return calcResult();
        }
@param reader
@param metadata
@return the best result given the detection results or {@link CSVResult#TEXT}
if the confidence is not above a threshold.
@throws IOException
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-text-module/src/main/java/org/apache/tika/parser/csv/CSVSniffer.java