All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nothome.delta.text.TextPatcher Maven / Gradle / Ivy

There is a newer version: 1.5
Show newest version
/*
 *
 * Copyright (c) 2008 Elias Ross
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 */
package com.nothome.delta.text;

import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.CharBuffer;

/**
 * Converts a text patch and source file to a resulting target file.
 */
public class TextPatcher {
  /** The source. */
  private SeekableSource source;
  /** The buf. */
  private CharBuffer buf = CharBuffer.allocate(1024);

  /**
   * Constructs a new TextPatcher with a generic source.
   *
   * @param source the source
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public TextPatcher(SeekableSource source) throws IOException {
    if (source == null)
      throw new NullPointerException("source");
    this.source = source;
  }

  /**
   * Constructs a new TextPatcher with a source to patch.
   *
   * @param source the source
   */
  public TextPatcher(CharSequence source) {
    this.source = new CharBufferSeekableSource(source);
  }

  /**
   * Patch from a string, return the result.
   *
   * @param patch the patch
   * @return the string
   */
  public String patch(CharSequence patch) {
    if (patch == null)
      throw new NullPointerException("patch");
    StringWriter sw = new StringWriter();
    try {
      patch(new StringReader(patch.toString()), sw);
      return sw.toString();
    } catch (IOException e) {
      throw new IllegalArgumentException("Invalid patch: " + e, e);
    }
  }

  /**
   * L.
   *
   * @param s the s
   * @return the long
   */
  private long l(String s) {
    return Long.parseLong(s, 16);
  }

  /**
   * Patches a source to an output file.
   *
   * @param patch the patch
   * @param out The output must be closed by the caller
   * @throws IOException Signals that an I/O exception has occurred.
   */
  public void patch(Reader patch, Writer out) throws IOException {
    if (patch == null)
      throw new NullPointerException("patch");
    if (out == null)
      throw new NullPointerException("out");
    BufferedReader br;
    if (patch instanceof BufferedReader)
      br = (BufferedReader) patch;
    else
      br = new BufferedReader(patch);
    String header = br.readLine();
    if (header == null)
      throw new EOFException();
    if (!header.equals(GDiffTextWriter.GDT)) {
      throw new IOException("Unexpected header: " + header);
    }
    String line;
    int lineCount = 0;
    while ((line = br.readLine()) != null) {
      lineCount++;
      if (line.length() == 0)
        throw new IOException("invalid empty line: " + lineCount);
      char c = line.charAt(0);
      if (c == GDiffTextWriter.COPY) {
        int i = line.indexOf(GDiffTextWriter.COMMA);
        if (i == -1)
          throw new IOException(", not found");
        long offset = l(line.substring(1, i));
        long length = l(line.substring(i + 1));
        source.seek(offset);
        copy(source, out, (int) length);
      } else if (c == GDiffTextWriter.DATA) {
        long dataSize = l(line.substring(1));
        copy(br, out, (int) dataSize);
        br.readLine();
      } else {
        throw new IOException("invalid patch command: " + lineCount);
      }
    }
    out.flush();
  }

  /**
   * Copy.
   *
   * @param source the source
   * @param out the out
   * @param length the length
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private void copy(Readable source, Writer out, int length) throws IOException {
    while (length > 0) {
      if (buf.limit() > length)
        buf.limit(length);
      int count = source.read(buf);
      if (count == -1)
        throw new IOException("EOF in chunk");
      buf.flip();
      out.append(buf);
      length -= count;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy