1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21package proguard.io; 22 23import proguard.classfile.ClassPool; 24 25import java.io.*; 26 27/** 28 * This DataEntryReader writes the manifest data entries that it reads to a 29 * given DataEntryWriter, updating their contents based on the renamed classes 30 * in the given ClassPool. 31 * 32 * @author Eric Lafortune 33 */ 34public class ManifestRewriter extends DataEntryRewriter 35{ 36 /** 37 * Creates a new ManifestRewriter. 38 */ 39 public ManifestRewriter(ClassPool classPool, 40 DataEntryWriter dataEntryWriter) 41 { 42 super(classPool, dataEntryWriter); 43 } 44 45 46 // Implementations for DataEntryRewriter. 47 48 protected void copyData(Reader reader, 49 Writer writer) 50 throws IOException 51 { 52 super.copyData(new SplitLineReader(reader), 53 new SplitLineWriter(writer)); 54 } 55 56 57 /** 58 * This Reader reads manifest files, joining any split lines. It replaces 59 * the allowed CR/LF/CR+LF alternatives by simple LF in the process. 60 */ 61 private static class SplitLineReader extends FilterReader 62 { 63 private static final int NONE = -2; 64 65 private int bufferedCharacter = NONE; 66 67 68 public SplitLineReader(Reader reader) 69 { 70 super(reader); 71 } 72 73 74 // Implementations for Reader. 75 76 public int read() throws IOException 77 { 78 while (true) 79 { 80 // Get the buffered character or the first character. 81 int c1 = bufferedCharacter != NONE ? 82 bufferedCharacter : 83 super.read(); 84 85 // Clear the buffered character. 86 bufferedCharacter = NONE; 87 88 // Return it if it's an ordinary character. 89 if (c1 != '\n' && c1 != '\r') 90 { 91 return c1; 92 } 93 94 // It's a newline. Read the second character to see if it's a 95 // continuation. 96 int c2 = super.read(); 97 98 // Skip any corresponding, redundant \n or \r. 99 if ((c2 == '\n' || c2 == '\r') && c1 != c2) 100 { 101 c2 = super.read(); 102 } 103 104 // Isn't it a continuation after all? 105 if (c2 != ' ') 106 { 107 // Buffer the second character and return a newline. 108 bufferedCharacter = c2; 109 return '\n'; 110 } 111 112 // Just continue after the continuation characters. 113 } 114 } 115 116 117 public int read(char[] cbuf, int off, int len) throws IOException 118 { 119 // Delegate to reading a single character at a time. 120 int count = 0; 121 while (count < len) 122 { 123 int c = read(); 124 if (c == -1) 125 { 126 break; 127 } 128 129 cbuf[off + count++] = (char)c; 130 } 131 132 return count; 133 } 134 135 136 public long skip(long n) throws IOException 137 { 138 // Delegate to reading a single character at a time. 139 int count = 0; 140 while (count < n) 141 { 142 int c = read(); 143 if (c == -1) 144 { 145 break; 146 } 147 148 count++; 149 } 150 151 return count; 152 } 153 } 154 155 156 /** 157 * This Writer writes manifest files, splitting any long lines. 158 */ 159 private static class SplitLineWriter extends FilterWriter 160 { 161 private int counter = 0; 162 163 164 public SplitLineWriter(Writer writer) 165 { 166 super(writer); 167 } 168 169 170 // Implementations for Reader. 171 172 public void write(int c) throws IOException 173 { 174 // TODO: We should actually count the Utf-8 bytes, not the characters. 175 if (c == '\n') 176 { 177 // Reset the character count. 178 counter = 0; 179 } 180 else if (counter == 70) 181 { 182 // Insert a newline and a space. 183 super.write('\n'); 184 super.write(' '); 185 186 counter = 2; 187 } 188 else 189 { 190 counter++; 191 } 192 193 super.write(c); 194 } 195 196 197 public void write(char[] cbuf, int off, int len) throws IOException 198 { 199 for (int count = 0; count < len; count++) 200 { 201 write(cbuf[off + count]); 202 } 203 } 204 205 206 public void write(String str, int off, int len) throws IOException 207 { 208 write(str.toCharArray(), off, len); 209 } 210 } 211}