| 475 | } |
| 476 | |
| 477 | private static class CharSequenceCharSource extends CharSource { |
| 478 | private static final Splitter LINE_SPLITTER = Splitter.onPattern("\r\n|\n|\r"); |
| 479 | |
| 480 | private final CharSequence seq; |
| 481 | |
| 482 | |
| 483 | protected CharSequenceCharSource(CharSequence seq) { |
| 484 | this.seq = checkNotNull(seq); |
| 485 | } |
| 486 | |
| 487 | @Override |
| 488 | public Reader openStream() { |
| 489 | return new CharSequenceReader(seq); |
| 490 | } |
| 491 | |
| 492 | @Override |
| 493 | public String read() { |
| 494 | return seq.toString(); |
| 495 | } |
| 496 | |
| 497 | @Override |
| 498 | public boolean isEmpty() { |
| 499 | return seq.length() == 0; |
| 500 | } |
| 501 | |
| 502 | @Override |
| 503 | public long length() { |
| 504 | return seq.length(); |
| 505 | } |
| 506 | |
| 507 | @Override |
| 508 | public Optional<Long> lengthIfKnown() { |
| 509 | return Optional.of((long) seq.length()); |
| 510 | } |
| 511 | |
| 512 | /** |
| 513 | * Returns an iterable over the lines in the string. If the string ends in a newline, a final |
| 514 | * empty string is not included to match the behavior of BufferedReader/LineReader.readLine(). |
| 515 | */ |
| 516 | |
| 517 | private Iterable<String> lines() { |
| 518 | return new Iterable<String>() { |
| 519 | @Override |
| 520 | public Iterator<String> iterator() { |
| 521 | return new AbstractIterator<String>() { |
| 522 | Iterator<String> lines = LINE_SPLITTER.split(seq).iterator(); |
| 523 | |
| 524 | |
| 525 | @Override |
| 526 | protected String computeNext() { |
| 527 | if (lines.hasNext()) { |
| 528 | String next = lines.next(); |
| 529 | // skip last line if it's empty |
| 530 | if (lines.hasNext() || !next.isEmpty()) { |
| 531 | return next; |
| 532 | } |
| 533 | } |
| 534 | return endOfData(); |