BaseConverter   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 98
ccs 43
cts 43
cp 1
rs 10
c 0
b 0
f 0
wmc 9

2 Methods

Rating   Name   Duplication   Size   Complexity  
B encode() 0 27 3
B decode() 0 33 6
1
<?php
2
3
/*
4
 * This file is part of the PHP EcryptFS library.
5
 * (c) 2017 by Dennis Birkholz
6
 * All rights reserved.
7
 * For the license to use this library, see the provided LICENSE file.
8
 */
9
10
namespace Iqb\Ecryptfs;
11
12
/**
13
 * Class to convert binary data to/from base256 to base64 with filename save alphabet.
14
 * Used to create encrypted filenames.
15
 *
16
 * @author Dennis Birkholz <[email protected]>
17
 */
18
final class BaseConverter
19
{
20
    const PORTABLE_FILENAME_CHARS = '-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
21
22
    const FILENAME_REVERSE_MAPPING = [
23
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */
24
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 15 */
25
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */
26
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 31 */
27
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 39 */
28
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, /* 47 */
29
        0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, /* 55 */
30
        0x0A, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 63 */
31
        0x00, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, /* 71 */
32
        0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, /* 79 */
33
        0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, /* 87 */
34
        0x23, 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, /* 95 */
35
        0x00, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, /* 103 */
36
        0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, /* 111 */
37
        0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, /* 119 */
38
        0x3D, 0x3E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, /* 123 - 255 initialized to 0x00 */
39
    ];
40
41
42
    /**
43
     * Decode the base64 encoded string into a base256 binary string
44
     *
45
     * @param string $encoded
46
     * @return string
47
     */
48 36
    public static function decode(string $encoded) : string
49
    {
50 36
        $srcSize = \strlen($encoded);
51 36
        $currentBitOffset = 0;
52 36
        $dstByteOffset = 0;
53 36
        $dst = [];
54
55 36
        for ($srcByteOffset=0; $srcByteOffset<$srcSize; $srcByteOffset++) {
56 36
            $byte = self::FILENAME_REVERSE_MAPPING[\ord($encoded[$srcByteOffset])];
57
58
            switch ($currentBitOffset) {
59 36
                case 0:
60 36
                    $dst[$dstByteOffset] = ($byte << 2);
61 36
                    $currentBitOffset = 6;
62 36
                    break;
63 36
                case 6:
64 36
                    $dst[$dstByteOffset++] |= ($byte >> 4);
65 36
                    $dst[$dstByteOffset] = (($byte & 0xF) << 4);
66 36
                    $currentBitOffset = 4;
67 36
                    break;
68 36
                case 4:
69 36
                    $dst[$dstByteOffset++] |= ($byte >> 2);
70 36
                    $dst[$dstByteOffset] = ($byte << 6);
71 36
                    $currentBitOffset = 2;
72 36
                    break;
73 36
                case 2:
74 36
                    $dst[$dstByteOffset++] |= ($byte);
75 36
                    $currentBitOffset = 0;
76 36
                    break;
77
            }
78
        }
79
80 36
        return \implode('', \array_map('\\chr', $dst));
81
    }
82
83
    /**
84
     * Encode a (base256) binary string into a base64 string (using the filename save alphabet)
85
     *
86
     * @param string $decoded
87
     * @return string
88
     */
89 36
    public static function encode(string $decoded) : string
90
    {
91 36
        $inputLength = \mb_strlen($decoded, '8bit');
92
93
        // Each encoded char holds only 6 bit of the original 8 bit
94
        // so a block of 3 original chars results in 4 encoded chars.
95
        // Pad the input with \0-bytes so string can be split in 3 char blocks.
96 36
        if (($inputLength % 3) > 0) {
97 36
            $padding = (3 - ($inputLength % 3));
98 36
            $decoded .= \str_repeat("\0", $padding);
99 36
            $inputLength += $padding;
100
        }
101
102 36
        $encoded = '';
103 36
        for ($i=0; $i<$inputLength; $i+=3) {
104 36
            $code1 = (\ord($decoded[$i]) >> 2) & 0x3F;
105 36
            $code2 = ((\ord($decoded[$i]) << 4) & 0x30) | ((\ord($decoded[$i+1]) >> 4) & 0x0F);
106 36
            $code3 = ((\ord($decoded[$i+1]) << 2) & 0x3C) | ((\ord($decoded[$i+2]) >> 6) & 0x03);
107 36
            $code4 = \ord($decoded[$i+2]) & 0x3F;
108
109 36
            $encoded .= self::PORTABLE_FILENAME_CHARS[$code1];
110 36
            $encoded .= self::PORTABLE_FILENAME_CHARS[$code2];
111 36
            $encoded .= self::PORTABLE_FILENAME_CHARS[$code3];
112 36
            $encoded .= self::PORTABLE_FILENAME_CHARS[$code4];
113
        }
114
115 36
        return $encoded;
116
    }
117
}
118