code: static void unescape(final Reader reader, final Writer writer) throws IOException {
  
          if (reader == null) {
              return;
          }
  
          boolean isQuoted = false;
  
          int c1, c2; // c1: current char, c2: next char
  
          c2 = reader.read();
  
          if (c2 < 0) {
              // Nothing to output
              return;
          } else if (c2 == DOUBLE_QUOTE) {
              c1 = c2;
              c2 = reader.read();
              if (c2 < 0) {
                  // Output is just a double-quote symbol
                  // (...which by the way is not a valid CSV value, as a " is non-alphanumeric)
                  writer.write(c1);
                  return;
              } else {
                  isQuoted = true;
              }
          }
  
          while (c2 >= 0) {
  
              c1 = c2;
              c2 = reader.read();
  
              /*
               * Shortcut: from an unescape point of view, we will ignore most characters
               */
              if (c1 != DOUBLE_QUOTE) {
                  writer.write(c1);
                  continue;
              }
  
              if (c2 < 0) {
  
                  if (!isQuoted) {
                      // Last char is double-quote. If last and value is quoted, ignore - if not, write.
                      writer.write(c1);
                  }
                  continue;
  
              } else if (c2 == DOUBLE_QUOTE) {
  
                  // This is an escaped double quote
  
                  writer.write(DOUBLE_QUOTE);
                  c1 = c2;
                  c2 = reader.read();
  
              } else {
                  // This is a non-escaped quote, which should only happen at the end, so this is actually
                  // non-valid CSV... but anyway, we will be lenient and just write it
  
                  writer.write(DOUBLE_QUOTE);
  
              }
  
          }
  
      }
docs: /*
  Perform an unescape operation based on a Reader, writing the results to a Writer.
  
  Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this
  is an inconvenience for the specific Reader implementation.