Completed
Push — master ( b3b676...8fdc21 )
by Alexey
06:06 queued 11s
created

ApkAlignmentExtraField::packLocalFileData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 1
b 0
f 1
1
<?php
2
3
namespace PhpZip\Model\Extra\Fields;
4
5
use PhpZip\Exception\ZipException;
6
use PhpZip\Model\Extra\ZipExtraField;
7
use PhpZip\Model\ZipEntry;
8
9
/**
10
 * Apk Alignment Extra Field.
11
 *
12
 * @see https://android.googlesource.com/platform/tools/apksig/+/master/src/main/java/com/android/apksig/ApkSigner.java
13
 * @see https://developer.android.com/studio/command-line/zipalign
14
 */
15
class ApkAlignmentExtraField implements ZipExtraField
16
{
17
    /**
18
     * @var int Extensible data block/field header ID used for storing
19
     *          information about alignment of uncompressed entries as
20
     *          well as for aligning the entries's data. See ZIP
21
     *          appnote.txt section 4.5 Extensible data fields.
22
     */
23
    const HEADER_ID = 0xd935;
24
25
    /**
26
     * @var int minimum size (in bytes) of the extensible data block/field used
27
     *          for alignment of uncompressed entries
28
     */
29
    const MIN_SIZE = 6;
30
31
    /** @var int */
32
    const ALIGNMENT_BYTES = 4;
33
34
    /** @var int */
35
    const COMMON_PAGE_ALIGNMENT_BYTES = 4096;
36
37
    /** @var int */
38
    private $multiple;
39
40
    /** @var int */
41
    private $padding;
42
43
    /**
44
     * @param int $multiple
45
     * @param int $padding
46
     */
47 13
    public function __construct($multiple, $padding)
48
    {
49 13
        $this->multiple = $multiple;
50 13
        $this->padding = $padding;
51 13
    }
52
53
    /**
54
     * Returns the Header ID (type) of this Extra Field.
55
     * The Header ID is an unsigned short integer (two bytes)
56
     * which must be constant during the life cycle of this object.
57
     *
58
     * @return int
59
     */
60 12
    public function getHeaderId()
61
    {
62 12
        return self::HEADER_ID;
63
    }
64
65
    /**
66
     * @return int
67
     */
68 6
    public function getMultiple()
69
    {
70 6
        return $this->multiple;
71
    }
72
73
    /**
74
     * @return int
75
     */
76 6
    public function getPadding()
77
    {
78 6
        return $this->padding;
79
    }
80
81
    /**
82
     * @param int $multiple
83
     */
84 1
    public function setMultiple($multiple)
85
    {
86 1
        $this->multiple = (int) $multiple;
87 1
    }
88
89
    /**
90
     * @param int $padding
91
     */
92 1
    public function setPadding($padding)
93
    {
94 1
        $this->padding = (int) $padding;
95 1
    }
96
97
    /**
98
     * Populate data from this array as if it was in local file data.
99
     *
100
     * @param string        $buffer the buffer to read data from
101
     * @param ZipEntry|null $entry
102
     *
103
     * @throws ZipException
104
     *
105
     * @return ApkAlignmentExtraField
106
     */
107 10
    public static function unpackLocalFileData($buffer, ZipEntry $entry = null)
108
    {
109 10
        $length = \strlen($buffer);
110
111 10
        if ($length < 2) {
112
            // This is APK alignment field.
113
            // FORMAT:
114
            //  * uint16 alignment multiple (in bytes)
115
            //  * remaining bytes -- padding to achieve alignment of data which starts after
116
            //    the extra field
117 1
            throw new ZipException(
118 1
                'Minimum 6 bytes of the extensible data block/field used for alignment of uncompressed entries.'
119
            );
120
        }
121 9
        $multiple = unpack('v', $buffer)[1];
122 9
        $padding = $length - 2;
123
124 9
        return new self($multiple, $padding);
125
    }
126
127
    /**
128
     * Populate data from this array as if it was in central directory data.
129
     *
130
     * @param string        $buffer the buffer to read data from
131
     * @param ZipEntry|null $entry
132
     *
133
     * @throws ZipException on error
134
     *
135
     * @return ApkAlignmentExtraField
136
     */
137 5
    public static function unpackCentralDirData($buffer, ZipEntry $entry = null)
138
    {
139 5
        return self::unpackLocalFileData($buffer, $entry);
140
    }
141
142
    /**
143
     * The actual data to put into local file data - without Header-ID
144
     * or length specifier.
145
     *
146
     * @return string the data
147
     */
148 9
    public function packLocalFileData()
149
    {
150 9
        return pack('vx' . $this->padding, $this->multiple);
151
    }
152
153
    /**
154
     * The actual data to put into central directory - without Header-ID or
155
     * length specifier.
156
     *
157
     * @return string the data
158
     */
159 5
    public function packCentralDirData()
160
    {
161 5
        return $this->packLocalFileData();
162
    }
163
164
    /**
165
     * @return string
166
     */
167 5
    public function __toString()
168
    {
169 5
        return sprintf(
170 5
            '0x%04x APK Alignment: Multiple=%d Padding=%d',
171 5
            self::HEADER_ID,
172 5
            $this->multiple,
173 5
            $this->padding
174
        );
175
    }
176
}
177