/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package proguard.io; import proguard.classfile.ClassPool; import java.io.*; /** * This DataEntryReader writes the manifest data entries that it reads to a * given DataEntryWriter, updating their contents based on the renamed classes * in the given ClassPool. * * @author Eric Lafortune */ public class ManifestRewriter extends DataEntryRewriter { /** * Creates a new ManifestRewriter. */ public ManifestRewriter(ClassPool classPool, DataEntryWriter dataEntryWriter) { super(classPool, dataEntryWriter); } // Implementations for DataEntryRewriter. protected void copyData(Reader reader, Writer writer) throws IOException { super.copyData(new SplitLineReader(reader), new SplitLineWriter(writer)); } /** * This Reader reads manifest files, joining any split lines. It replaces * the allowed CR/LF/CR+LF alternatives by simple LF in the process. */ private static class SplitLineReader extends FilterReader { private static final int NONE = -2; private int bufferedCharacter = NONE; public SplitLineReader(Reader reader) { super(reader); } // Implementations for Reader. public int read() throws IOException { while (true) { // Get the buffered character or the first character. int c1 = bufferedCharacter != NONE ? bufferedCharacter : super.read(); // Clear the buffered character. bufferedCharacter = NONE; // Return it if it's an ordinary character. if (c1 != '\n' && c1 != '\r') { return c1; } // It's a newline. Read the second character to see if it's a // continuation. int c2 = super.read(); // Skip any corresponding, redundant \n or \r. if ((c2 == '\n' || c2 == '\r') && c1 != c2) { c2 = super.read(); } // Isn't it a continuation after all? if (c2 != ' ') { // Buffer the second character and return a newline. bufferedCharacter = c2; return '\n'; } // Just continue after the continuation characters. } } public int read(char[] cbuf, int off, int len) throws IOException { // Delegate to reading a single character at a time. int count = 0; while (count < len) { int c = read(); if (c == -1) { break; } cbuf[off + count++] = (char)c; } return count; } public long skip(long n) throws IOException { // Delegate to reading a single character at a time. int count = 0; while (count < n) { int c = read(); if (c == -1) { break; } count++; } return count; } } /** * This Writer writes manifest files, splitting any long lines. */ private static class SplitLineWriter extends FilterWriter { private int counter = 0; public SplitLineWriter(Writer writer) { super(writer); } // Implementations for Reader. public void write(int c) throws IOException { // TODO: We should actually count the Utf-8 bytes, not the characters. if (c == '\n') { // Reset the character count. counter = 0; } else if (counter == 70) { // Insert a newline and a space. super.write('\n'); super.write(' '); counter = 2; } else { counter++; } super.write(c); } public void write(char[] cbuf, int off, int len) throws IOException { for (int count = 0; count < len; count++) { write(cbuf[off + count]); } } public void write(String str, int off, int len) throws IOException { write(str.toCharArray(), off, len); } } }