aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/ziputils/DataDescriptor.java
blob: ee7fbca022c939e4b48f0a142dce2d17fcc1fe80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.android.ziputils;

import static java.nio.ByteOrder.LITTLE_ENDIAN;

import java.nio.ByteBuffer;

/**
 * Provides a view of a data descriptor record, for a zip file entry.
 */
public class DataDescriptor extends View<DataDescriptor> {
  private boolean hasMarker;

  /**
   * Returns a {@code DataDescriptor} view of the given buffer. The buffer is assumed to contain a
   * valid "data descriptor" record beginning at the buffers current position.
   *
   * @param buffer containing the data of a data descriptor record.
   * @return a {@code DataDescriptor} of the data at the current position of the given byte
   * buffer.
   */
  public static DataDescriptor viewOf(ByteBuffer buffer) {
    DataDescriptor view = new DataDescriptor(buffer.slice());
    int size = view.getSize();
    view.buffer.position(0).limit(size);
    buffer.position(buffer.position() + size);
    return view;
  }

  private DataDescriptor(ByteBuffer buffer) {
    super(buffer);
    hasMarker = buffer.getInt(0) == SIGNATURE;
  }

  /**
   * Creates a {@code DataDescriptor} with a heap allocated buffer.
   *
   * @return a {@code DataDescriptor} with a heap allocated buffer.
   */
  public static DataDescriptor allocate() {
    ByteBuffer buffer = ByteBuffer.allocate(SIZE).order(LITTLE_ENDIAN);
    return new DataDescriptor(buffer).init();
  }

  /**
   * Creates a {@code DataDescriptor} view over a writable buffer. The given buffers position is
   * advanced by the number of bytes consumed by the view.
   *
   * @param buffer buffer to hold data for the "data descriptor" record.
   * @return a {@code DataDescriptor} with a heap allocated buffer.
   */
  public static DataDescriptor view(ByteBuffer buffer) {
    DataDescriptor view = new DataDescriptor(buffer.slice()).init();
    buffer.position(buffer.position() + SIZE);
    return view;
  }

  /**
   * Copies this {@code DataDescriptor} into a writable buffer. The copy is made at the
   * buffer's current position, and the position is advanced, by the size of the copy.
   *
   * @param buffer buffer to hold data for the copy.
   * @return a {@code DataDescriptor} backed by the given buffer.
   */
  public DataDescriptor copy(ByteBuffer buffer) {
    int size = getSize();
    DataDescriptor view = new DataDescriptor(buffer.slice());
    this.buffer.rewind();
    view.buffer.put(this.buffer).flip();
    buffer.position(buffer.position() + size);
    this.buffer.rewind();
    return view;
  }

  private DataDescriptor init() {
    buffer.putInt(0, SIGNATURE);
    hasMarker = true;
    buffer.limit(SIZE);
    return this;
  }

  /**
   * Data descriptor signature.
   */
  public static final int SIGNATURE = 0x08074b50; // 134695760L

  /**
   * Data descriptor size (including optional signature).
   */
  public static final int SIZE = 16;

  /**
   * For accessing the data descriptor signature, with the
   * {@link View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)}
   * and {@link View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, int)}
   * methods.
   */
  public static final IntFieldId<DataDescriptor> EXTSIG = new IntFieldId<>(0);

  /**
   * For accessing the "crc" data descriptor field, with the
   * {@link View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)}
   * and {@link View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, int)}
   * methods.
   */
  public static final IntFieldId<DataDescriptor> EXTCRC = new IntFieldId<>(4);

  /**
   * For accessing the "compressed size" data descriptor field, with the
   * {@link View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)}
   * and {@link View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, int)}
   * methods.
   */
  public static final IntFieldId<DataDescriptor> EXTSIZ = new IntFieldId<>(8);

  /**
   * For accessing the "uncompressed size" data descriptor field, with the
   * {@link View#get(com.google.devtools.build.android.ziputils.View.IntFieldId)}
   * and {@link View#set(com.google.devtools.build.android.ziputils.View.IntFieldId, int)}
   * methods.
   */
  public static final IntFieldId<DataDescriptor> EXTLEN = new IntFieldId<>(12);


  /**
   * Overrides the generic field getter, to handle optionality of signature.
   * @see View#get(com.google.devtools.build.android.ziputils.View.IntFieldId).
   */
  @Override  @SuppressWarnings("unchecked") // safe by specification (FieldId.type()).
  public int get(IntFieldId<? extends DataDescriptor> item) {
    int address = hasMarker ? item.address() : (item.address() - 4);
    return address < 0 ? -1 : buffer.getInt(address);
  }

  /**
   * Returns whether this data descriptor has the optional signature.
   * @return {@code true} if this data descriptor has a signature, {@code false} otherwise.
   */
  public final boolean hasMarker() {
    return hasMarker;
  }

  /**
   * Returns the size of this data descriptor.
   * @return 12, or 16, depending on whether or not this data descriptor has a signature.
   */
  public final int getSize() {
    return hasMarker ? SIZE : SIZE - 4;
  }
}