Home | History | Annotate | Download | only in io
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) 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  */
     21 package proguard.io;
     22 
     23 import proguard.classfile.ClassPool;
     24 
     25 import 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  */
     34 public 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 }