Home » openjdk-7 » java » util » jar » [javadoc | source]

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package java.util.jar;
   19   
   20   import java.io.IOException;
   21   import java.nio.ByteBuffer;
   22   import java.nio.CharBuffer;
   23   import java.nio.charset.CharsetDecoder;
   24   import java.nio.charset.CoderResult;
   25   import java.util.Map;
   26   
   27   import org.apache.harmony.archive.internal.nls.Messages;
   28   import org.apache.harmony.luni.util.ThreadLocalCache;
   29   
   30   class InitManifest {
   31   
   32       private byte[] buf;
   33   
   34       private int pos;
   35   
   36       Attributes.Name name;
   37   
   38       String value;
   39   
   40       CharsetDecoder decoder = ThreadLocalCache.utf8Decoder.get();
   41       CharBuffer cBuf = ThreadLocalCache.charBuffer.get();
   42   
   43       InitManifest(byte[] buf, Attributes main, Attributes.Name ver)
   44               throws IOException {
   45   
   46           this.buf = buf;
   47   
   48           // check a version attribute
   49           if (!readHeader() || (ver != null && !name.equals(ver))) {
   50               throw new IOException(Messages.getString(
   51                       "archive.2D", ver)); //$NON-NLS-1$
   52           }
   53   
   54           main.put(name, value);
   55           while (readHeader()) {
   56               main.put(name, value);
   57           }
   58       }
   59   
   60       void initEntries(Map<String, Attributes> entries,
   61               Map<String, Manifest.Chunk> chunks) throws IOException {
   62   
   63           int mark = pos;
   64           while (readHeader()) {
   65               if (!Attributes.Name.NAME.equals(name)) {
   66                   throw new IOException(Messages.getString("archive.23")); //$NON-NLS-1$
   67               }
   68               String entryNameValue = value;
   69   
   70               Attributes entry = entries.get(entryNameValue);
   71               if (entry == null) {
   72                   entry = new Attributes(12);
   73               }
   74   
   75               while (readHeader()) {
   76                   entry.put(name, value);
   77               }
   78   
   79               if (chunks != null) {
   80                   if (chunks.get(entryNameValue) != null) {
   81                       // TODO A bug: there might be several verification chunks for
   82                       // the same name. I believe they should be used to update
   83                       // signature in order of appearance; there are two ways to fix
   84                       // this: either use a list of chunks, or decide on used
   85                       // signature algorithm in advance and reread the chunks while
   86                       // updating the signature; for now a defensive error is thrown
   87                       throw new IOException(Messages.getString("archive.34")); //$NON-NLS-1$
   88                   }
   89                   chunks.put(entryNameValue, new Manifest.Chunk(mark, pos));
   90                   mark = pos;
   91               }
   92   
   93               entries.put(entryNameValue, entry);
   94           }
   95       }
   96   
   97       int getPos() {
   98           return pos;
   99       }
  100   
  101       /**
  102        * Number of subsequent line breaks.
  103        */
  104       int linebreak = 0;
  105   
  106       /**
  107        * Read a single line from the manifest buffer.
  108        */
  109       private boolean readHeader() throws IOException {
  110           if (linebreak > 1) {
  111               // break a section on an empty line
  112               linebreak = 0;
  113               return false;
  114           }
  115           readName();
  116           linebreak = 0;
  117           readValue();
  118           // if the last line break is missed, the line
  119           // is ignored by the reference implementation
  120           return linebreak > 0;
  121       }
  122   
  123       private byte[] wrap(int mark, int pos) {
  124           byte[] buffer = new byte[pos - mark];
  125           System.arraycopy(buf, mark, buffer, 0, pos - mark);
  126           return buffer;
  127       }
  128   
  129       private void readName() throws IOException {
  130           int i = 0;
  131           int mark = pos;
  132   
  133           while (pos < buf.length) {
  134               byte b = buf[pos++];
  135   
  136               if (b == ':') {
  137                   byte[] nameBuffer = wrap(mark, pos - 1);
  138   
  139                   if (buf[pos++] != ' ') {
  140                       throw new IOException(Messages.getString(
  141                               "archive.30", nameBuffer)); //$NON-NLS-1$
  142                   }
  143   
  144                   name = new Attributes.Name(nameBuffer);
  145                   return;
  146               }
  147   
  148               if (!((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_'
  149                       || b == '-' || (b >= '0' && b <= '9'))) {
  150                   throw new IOException(Messages.getString("archive.30", b)); //$NON-NLS-1$
  151               }
  152           }
  153           if (i > 0) {
  154               throw new IOException(Messages.getString(
  155                       "archive.30", wrap(mark, buf.length))); //$NON-NLS-1$
  156           }
  157       }
  158   
  159       private void readValue() throws IOException {
  160           byte next;
  161           boolean lastCr = false;
  162           int mark = pos;
  163           int last = pos;
  164   
  165           decoder.reset();
  166           cBuf.clear();
  167   
  168           while (pos < buf.length) {
  169               next = buf[pos++];
  170   
  171               switch (next) {
  172               case 0:
  173                   throw new IOException(Messages.getString("archive.2F")); //$NON-NLS-1$
  174               case '\n':
  175                   if (lastCr) {
  176                       lastCr = false;
  177                   } else {
  178                       linebreak++;
  179                   }
  180                   continue;
  181               case '\r':
  182                   lastCr = true;
  183                   linebreak++;
  184                   continue;
  185               case ' ':
  186                   if (linebreak == 1) {
  187                       decode(mark, last, false);
  188                       mark = pos;
  189                       linebreak = 0;
  190                       continue;
  191                   }
  192               }
  193   
  194               if (linebreak >= 1) {
  195                   pos--;
  196                   break;
  197               }
  198               last = pos;
  199           }
  200   
  201           decode(mark, last, true);
  202           while (CoderResult.OVERFLOW == decoder.flush(cBuf)) {
  203               enlargeBuffer();
  204           }
  205           value = new String(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
  206       }
  207   
  208       private void decode(int mark, int pos, boolean endOfInput)
  209               throws IOException {
  210           ByteBuffer bBuf = ByteBuffer.wrap(buf, mark, pos - mark);
  211           while (CoderResult.OVERFLOW == decoder.decode(bBuf, cBuf, endOfInput)) {
  212               enlargeBuffer();
  213           }
  214       }
  215   
  216       private void enlargeBuffer() {
  217           CharBuffer newBuf = CharBuffer.allocate(cBuf.capacity() * 2);
  218           newBuf.put(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
  219           cBuf = newBuf;
  220           ThreadLocalCache.charBuffer.set(cBuf);
  221       }
  222   }

Home » openjdk-7 » java » util » jar » [javadoc | source]