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}