BCGcode128::extractTilde()   B
last analyzed

Complexity

Conditions 8
Paths 7

Size

Total Lines 26
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 19
nc 7
nop 2
dl 0
loc 26
rs 8.4444
c 0
b 0
f 0
1
<?php
2
namespace tinymeng\code\Gateways\barcode;
3
4
/**
5
 *--------------------------------------------------------------------
6
 *
7
 * Sub-Class - Code 128, A, B, C
8
 *
9
 * # Code C Working properly only on PHP4 or PHP5.0.3+ due to bug :
10
 * http://bugs.php.net/bug.php?id=28862
11
 *
12
 * !! Warning !!
13
 * If you display the checksum on the label, you may obtain
14
 * some garbage since some characters are not displayable.
15
 *
16
 *--------------------------------------------------------------------
17
 * Copyright (C) Jean-Sebastien Goupil
18
 * http://www.barcodephp.com
19
 */
20
21
define('CODE128_A',    1);            // Table A
22
define('CODE128_B',    2);            // Table B
23
define('CODE128_C',    3);            // Table C
24
class BCGcode128 extends BCGBarcode1D {
25
    const KEYA_FNC3 = 96;
26
    const KEYA_FNC2 = 97;
27
    const KEYA_SHIFT = 98;
28
    const KEYA_CODEC = 99;
29
    const KEYA_CODEB = 100;
30
    const KEYA_FNC4 = 101;
31
    const KEYA_FNC1 = 102;
32
33
    const KEYB_FNC3 = 96;
34
    const KEYB_FNC2 = 97;
35
    const KEYB_SHIFT = 98;
36
    const KEYB_CODEC = 99;
37
    const KEYB_FNC4 = 100;
38
    const KEYB_CODEA = 101;
39
    const KEYB_FNC1 = 102;
40
41
    const KEYC_CODEB = 100;
42
    const KEYC_CODEA = 101;
43
    const KEYC_FNC1 = 102;
44
45
    const KEY_STARTA = 103;
46
    const KEY_STARTB = 104;
47
    const KEY_STARTC = 105;
48
49
    const KEY_STOP = 106;
50
51
    protected $keysA, $keysB, $keysC;
52
    private $starting_text;
53
    private $indcheck, $data, $lastTable;
54
    private $tilde;
55
56
    private $shift;
57
    private $latch;
58
    private $fnc;
59
60
    private $METHOD            = null; // Array of method available to create Code128 (CODE128_A, CODE128_B, CODE128_C)
61
62
    /**
63
     * Constructor.
64
     *
65
     * @param char $start
0 ignored issues
show
Bug introduced by
The type tinymeng\code\Gateways\barcode\char was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
66
     */
67
    public function __construct($start = null) {
68
        parent::__construct();
69
70
        /* CODE 128 A */
71
        $this->keysA = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
72
        for ($i = 0; $i < 32; $i++) {
73
            $this->keysA .= chr($i);
74
        }
75
76
        /* CODE 128 B */
77
        $this->keysB = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' . chr(127);
78
79
        /* CODE 128 C */
80
        $this->keysC = '0123456789';
81
82
        $this->code = array(
83
            '101111',   /* 00 */
84
            '111011',   /* 01 */
85
            '111110',   /* 02 */
86
            '010112',   /* 03 */
87
            '010211',   /* 04 */
88
            '020111',   /* 05 */
89
            '011102',   /* 06 */
90
            '011201',   /* 07 */
91
            '021101',   /* 08 */
92
            '110102',   /* 09 */
93
            '110201',   /* 10 */
94
            '120101',   /* 11 */
95
            '001121',   /* 12 */
96
            '011021',   /* 13 */
97
            '011120',   /* 14 */
98
            '002111',   /* 15 */
99
            '012011',   /* 16 */
100
            '012110',   /* 17 */
101
            '112100',   /* 18 */
102
            '110021',   /* 19 */
103
            '110120',   /* 20 */
104
            '102101',   /* 21 */
105
            '112001',   /* 22 */
106
            '201020',   /* 23 */
107
            '200111',   /* 24 */
108
            '210011',   /* 25 */
109
            '210110',   /* 26 */
110
            '201101',   /* 27 */
111
            '211001',   /* 28 */
112
            '211100',   /* 29 */
113
            '101012',   /* 30 */
114
            '101210',   /* 31 */
115
            '121010',   /* 32 */
116
            '000212',   /* 33 */
117
            '020012',   /* 34 */
118
            '020210',   /* 35 */
119
            '001202',   /* 36 */
120
            '021002',   /* 37 */
121
            '021200',   /* 38 */
122
            '100202',   /* 39 */
123
            '120002',   /* 40 */
124
            '120200',   /* 41 */
125
            '001022',   /* 42 */
126
            '001220',   /* 43 */
127
            '021020',   /* 44 */
128
            '002012',   /* 45 */
129
            '002210',   /* 46 */
130
            '022010',   /* 47 */
131
            '202010',   /* 48 */
132
            '100220',   /* 49 */
133
            '120020',   /* 50 */
134
            '102002',   /* 51 */
135
            '102200',   /* 52 */
136
            '102020',   /* 53 */
137
            '200012',   /* 54 */
138
            '200210',   /* 55 */
139
            '220010',   /* 56 */
140
            '201002',   /* 57 */
141
            '201200',   /* 58 */
142
            '221000',   /* 59 */
143
            '203000',   /* 60 */
144
            '110300',   /* 61 */
145
            '320000',   /* 62 */
146
            '000113',   /* 63 */
147
            '000311',   /* 64 */
148
            '010013',   /* 65 */
149
            '010310',   /* 66 */
150
            '030011',   /* 67 */
151
            '030110',   /* 68 */
152
            '001103',   /* 69 */
153
            '001301',   /* 70 */
154
            '011003',   /* 71 */
155
            '011300',   /* 72 */
156
            '031001',   /* 73 */
157
            '031100',   /* 74 */
158
            '130100',   /* 75 */
159
            '110003',   /* 76 */
160
            '302000',   /* 77 */
161
            '130001',   /* 78 */
162
            '023000',   /* 79 */
163
            '000131',   /* 80 */
164
            '010031',   /* 81 */
165
            '010130',   /* 82 */
166
            '003101',   /* 83 */
167
            '013001',   /* 84 */
168
            '013100',   /* 85 */
169
            '300101',   /* 86 */
170
            '310001',   /* 87 */
171
            '310100',   /* 88 */
172
            '101030',   /* 89 */
173
            '103010',   /* 90 */
174
            '301010',   /* 91 */
175
            '000032',   /* 92 */
176
            '000230',   /* 93 */
177
            '020030',   /* 94 */
178
            '003002',   /* 95 */
179
            '003200',   /* 96 */
180
            '300002',   /* 97 */
181
            '300200',   /* 98 */
182
            '002030',   /* 99 */
183
            '003020',   /* 100*/
184
            '200030',   /* 101*/
185
            '300020',   /* 102*/
186
            '100301',   /* 103*/
187
            '100103',   /* 104*/
188
            '100121',   /* 105*/
189
            '122000'    /*STOP*/
190
        );
191
        $this->setStart($start);
192
        $this->setTilde(true);
193
194
        // Latches and Shifts
195
        $this->latch = array(
196
            array(null,             self::KEYA_CODEB,   self::KEYA_CODEC),
197
            array(self::KEYB_CODEA, null,               self::KEYB_CODEC),
198
            array(self::KEYC_CODEA, self::KEYC_CODEB,   null)
199
        );
200
        $this->shift = array(
201
            array(null,             self::KEYA_SHIFT),
202
            array(self::KEYB_SHIFT, null)
203
        );
204
        $this->fnc = array(
205
            array(self::KEYA_FNC1,  self::KEYA_FNC2,    self::KEYA_FNC3,    self::KEYA_FNC4),
206
            array(self::KEYB_FNC1,  self::KEYB_FNC2,    self::KEYB_FNC3,    self::KEYB_FNC4),
207
            array(self::KEYC_FNC1,  null,               null,               null)
208
        );
209
210
        // Method available
211
        $this->METHOD        = array(CODE128_A => 'A', CODE128_B => 'B', CODE128_C => 'C');
212
    }
213
214
    /**
215
     * Specifies the start code. Can be 'A', 'B', 'C', or null
216
     *  - Table A: Capitals + ASCII 0-31 + punct
217
     *  - Table B: Capitals + LowerCase + punct
218
     *  - Table C: Numbers
219
     *
220
     * If null is specified, the table selection is automatically made.
221
     * The default is null.
222
     *
223
     * @param string $table
224
     */
225
    public function setStart($table) {
226
        if ($table !== 'A' && $table !== 'B' && $table !== 'C' && $table !== null) {
227
            throw new BCGArgumentException('The starting table must be A, B, C or null.', 'table');
228
        }
229
230
        $this->starting_text = $table;
231
    }
232
233
    /**
234
     * Gets the tilde.
235
     *
236
     * @return bool
237
     */
238
    public function getTilde() {
239
        return $this->tilde;
240
    }
241
242
    /**
243
     * Accepts tilde to be process as a special character.
244
     * If true, you can do this:
245
     *  - ~~     : to make ONE tilde
246
     *  - ~Fx    : to insert FCNx. x is equal from 1 to 4.
247
     *
248
     * @param boolean $accept
249
     */
250
    public function setTilde($accept) {
251
        $this->tilde = (bool)$accept;
252
    }
253
254
    /**
255
     * Parses the text before displaying it.
256
     *
257
     * @param mixed $text
258
     */
259
    public function parse($text) {
260
        $this->setStartFromText($text);
261
262
        $this->text = '';
263
        $seq = '';
264
265
        $currentMode = $this->starting_text;
266
267
        // Here, we format correctly what the user gives.
268
        if (!is_array($text)) {
269
            $seq = $this->getSequence($text, $currentMode);
270
            $this->text = $text;
271
        } else {
272
            // This loop checks for UnknownText AND raises an exception if a character is not allowed in a table
273
            reset($text);
274
            while (list($key1, $val1) = each($text)) {     // We take each value
275
                if (!is_array($val1)) {                    // This is not a table
276
                    if (is_string($val1)) {                // If it's a string, parse as unknown
277
                        $seq .= $this->getSequence($val1, $currentMode);
278
                        $this->text .= $val1;
279
                    } else {
280
                        // it's the case of "array(ENCODING, 'text')"
281
                        // We got ENCODING in $val1, calling 'each' again will get 'text' in $val2
282
                        list($key2, $val2) = each($text);
283
                        $seq .= $this->{'setParse' . $this->METHOD[$val1]}($val2, $currentMode);
284
                        $this->text .= $val2;
285
                    }
286
                } else {                        // The method is specified
287
                    // $val1[0] = ENCODING
288
                    // $val1[1] = 'text'
289
                    $value = isset($val1[1]) ? $val1[1] : '';    // If data available
290
                    $seq .= $this->{'setParse' . $this->METHOD[$val1[0]]}($value, $currentMode);
291
                    $this->text .= $value;
292
                }
293
            }
294
        }
295
296
        if ($seq !== '') {
297
            $bitstream = $this->createBinaryStream($this->text, $seq);
298
            $this->setData($bitstream);
299
        }
300
301
        $this->addDefaultLabel();
302
    }
303
304
    /**
305
     * Draws the barcode.
306
     *
307
     * @param resource $im
308
     */
309
    public function draw($im) {
310
        $c = count($this->data);
311
        for ($i = 0; $i < $c; $i++) {
312
            $this->drawChar($im, $this->data[$i], true);
313
        }
314
315
        $this->drawChar($im, '1', true);
316
        $this->drawText($im, 0, 0, $this->positionX, $this->thickness);
317
    }
318
319
    /**
320
     * Returns the maximal size of a barcode.
321
     *
322
     * @param int $w
323
     * @param int $h
324
     * @return int[]
325
     */
326
    public function getDimension($w, $h) {
327
        // Contains start + text + checksum + stop
328
        $textlength = count($this->data) * 11;
329
        $endlength = 2; // + final bar
330
331
        $w += $textlength + $endlength;
332
        $h += $this->thickness;
333
        return parent::getDimension($w, $h);
334
    }
335
336
    /**
337
     * Validates the input.
338
     */
339
    protected function validate() {
340
        $c = count($this->data);
341
        if ($c === 0) {
342
            throw new BCGParseException('code128', 'No data has been entered.');
0 ignored issues
show
Bug introduced by
The type tinymeng\code\Gateways\barcode\BCGParseException was not found. Did you mean BCGParseException? If so, make sure to prefix the type with \.
Loading history...
343
        }
344
345
        parent::validate();
346
    }
347
348
    /**
349
     * Overloaded method to calculate checksum.
350
     */
351
    protected function calculateChecksum() {
352
        // Checksum
353
        // First Char (START)
354
        // + Starting with the first data character following the start character,
355
        // take the value of the character (between 0 and 102, inclusive) multiply
356
        // it by its character position (1) and add that to the running checksum.
357
        // Modulated 103
358
        $this->checksumValue = $this->indcheck[0];
359
        $c = count($this->indcheck);
360
        for ($i = 1; $i < $c; $i++) {
361
            $this->checksumValue += $this->indcheck[$i] * $i;
362
        }
363
364
        $this->checksumValue = $this->checksumValue % 103;
365
    }
366
367
    /**
368
     * Overloaded method to display the checksum.
369
     */
370
    protected function processChecksum() {
371
        if ($this->checksumValue === false) { // Calculate the checksum only once
372
            $this->calculateChecksum();
373
        }
374
375
        if ($this->checksumValue !== false) {
0 ignored issues
show
introduced by
The condition $this->checksumValue !== false is always true.
Loading history...
376
            if ($this->lastTable === 'C') {
377
                return (string)$this->checksumValue;
378
            }
379
380
            return $this->{'keys' . $this->lastTable}[$this->checksumValue];
381
        }
382
383
        return false;
384
    }
385
386
    /**
387
     * Specifies the starting_text table if none has been specified earlier.
388
     *
389
     * @param string $text
390
     */
391
    private function setStartFromText($text) {
392
        if ($this->starting_text === null) {
393
            // If we have a forced table at the start, we get that one...
394
            if (is_array($text)) {
0 ignored issues
show
introduced by
The condition is_array($text) is always false.
Loading history...
395
                if (is_array($text[0])) {
396
                    // Code like array(array(ENCODING, ''))
397
                    $this->starting_text = $this->METHOD[$text[0][0]];
398
                    return;
399
                } else {
400
                    if (is_string($text[0])) {
401
                        // Code like array('test') (Automatic text)
402
                        $text = $text[0];
403
                    } else {
404
                        // Code like array(ENCODING, '')
405
                        $this->starting_text = $this->METHOD[$text[0]];
406
                        return;
407
                    }
408
                }
409
            }
410
411
            // At this point, we had an "automatic" table selection...
412
            // If we can get at least 4 numbers, go in C; otherwise go in B.
413
            $tmp = preg_quote($this->keysC, '/');
414
            $length = strlen($text);
415
            if ($length >= 4 && preg_match('/[' . $tmp . ']/', substr($text, 0, 4))) {
416
                $this->starting_text = 'C';
417
            } else {
418
                if ($length > 0 && strpos($this->keysB, $text[0]) !== false) {
419
                    $this->starting_text = 'B';
420
                } else {
421
                    $this->starting_text = 'A';
422
                }
423
            }
424
        }
425
    }
426
427
    /**
428
     * Extracts the ~ value from the $text at the $pos.
429
     * If the tilde is not ~~, ~F1, ~F2, ~F3, ~F4; an error is raised.
430
     *
431
     * @param string $text
432
     * @param int $pos
433
     * @return string
434
     */
435
    private static function extractTilde($text, $pos) {
436
        if ($text[$pos] === '~') {
437
            if (isset($text[$pos + 1])) {
438
                // Do we have a tilde?
439
                if ($text[$pos + 1] === '~') {
440
                    return '~~';
441
                } elseif ($text[$pos + 1] === 'F') {
442
                    // Do we have a number after?
443
                    if (isset($text[$pos + 2])) {
444
                        $v = intval($text[$pos + 2]);
445
                        if ($v >= 1 && $v <= 4) {
446
                            return '~F' . $v;
447
                        } else {
448
                            throw new BCGParseException('code128', 'Bad ~F. You must provide a number from 1 to 4.');
449
                        }
450
                    } else {
451
                        throw new BCGParseException('code128', 'Bad ~F. You must provide a number from 1 to 4.');
452
                    }
453
                } else {
454
                    throw new BCGParseException('code128', 'Wrong code after the ~.');
455
                }
456
            } else {
457
                throw new BCGParseException('code128', 'Wrong code after the ~.');
458
            }
459
        } else {
460
            throw new BCGParseException('code128', 'There is no ~ at this location.');
461
        }
462
    }
463
464
    /**
465
     * Gets the "dotted" sequence for the $text based on the $currentMode.
466
     * There is also a check if we use the special tilde ~
467
     *
468
     * @param string $text
469
     * @param string $currentMode
470
     * @return string
471
     */
472
    private function getSequenceParsed($text, $currentMode) {
473
        if ($this->tilde) {
474
            $sequence = '';
475
            $previousPos = 0;
476
            while (($pos = strpos($text, '~', $previousPos)) !== false) {
477
                $tildeData = self::extractTilde($text, $pos);
478
479
                $simpleTilde = ($tildeData === '~~');
480
                if ($simpleTilde && $currentMode !== 'B') {
481
                    throw new BCGParseException('code128', 'The Table ' . $currentMode . ' doesn\'t contain the character ~.');
482
                }
483
484
                // At this point, we know we have ~Fx
485
                if ($tildeData !== '~F1' && $currentMode === 'C') {
486
                    // The mode C doesn't support ~F2, ~F3, ~F4
487
                    throw new BCGParseException('code128', 'The Table C doesn\'t contain the function ' . $tildeData . '.');
488
                }
489
490
                $length = $pos - $previousPos;
491
                if ($currentMode === 'C') {
492
                    if ($length % 2 === 1) {
493
                        throw new BCGParseException('code128', 'The text "' . $text . '" must have an even number of character to be encoded in Table C.');
494
                    }
495
                }
496
497
                $sequence .= str_repeat('.', $length);
498
                $sequence .= '.';
499
                $sequence .= (!$simpleTilde) ? 'F' : '';
500
                $previousPos = $pos + strlen($tildeData);
501
            }
502
503
            // Flushing
504
            $length = strlen($text) - $previousPos;
505
            if ($currentMode === 'C') {
506
                if ($length % 2 === 1) {
507
                    throw new BCGParseException('code128', 'The text "' . $text . '" must have an even number of character to be encoded in Table C.');
508
                }
509
            }
510
511
            $sequence .= str_repeat('.', $length);
512
513
            return $sequence;
514
        } else {
515
            return str_repeat('.', strlen($text));
516
        }
517
    }
518
519
    /**
520
     * Parses the text and returns the appropriate sequence for the Table A.
521
     *
522
     * @param string $text
523
     * @param string $currentMode
524
     * @return string
525
     */
526
    private function setParseA($text, &$currentMode) {
527
        $tmp = preg_quote($this->keysA, '/');
528
529
        // If we accept the ~ for special character, we must allow it.
530
        if ($this->tilde) {
531
            $tmp .= '~';
532
        }
533
534
        $match = array();
535
        if (preg_match('/[^' . $tmp . ']/', $text, $match) === 1) {
536
            // We found something not allowed
537
            throw new BCGParseException('code128', 'The text "' . $text . '" can\'t be parsed with the Table A. The character "' . $match[0] . '" is not allowed.');
538
        } else {
539
            $latch = ($currentMode === 'A') ? '' : '0';
540
            $currentMode = 'A';
541
542
            return $latch . $this->getSequenceParsed($text, $currentMode);
543
        }
544
    }
545
546
    /**
547
     * Parses the text and returns the appropriate sequence for the Table B.
548
     *
549
     * @param string $text
550
     * @param string $currentMode
551
     * @return string
552
     */
553
    private function setParseB($text, &$currentMode) {
554
        $tmp = preg_quote($this->keysB, '/');
555
556
        $match = array();
557
        if (preg_match('/[^' . $tmp . ']/', $text, $match) === 1) {
558
            // We found something not allowed
559
            throw new BCGParseException('code128', 'The text "' . $text . '" can\'t be parsed with the Table B. The character "' . $match[0] . '" is not allowed.');
560
        } else {
561
            $latch = ($currentMode === 'B') ? '' : '1';
562
            $currentMode = 'B';
563
564
            return $latch . $this->getSequenceParsed($text, $currentMode);
565
        }
566
    }
567
568
    /**
569
     * Parses the text and returns the appropriate sequence for the Table C.
570
     *
571
     * @param string $text
572
     * @param string $currentMode
573
     * @return string
574
     */
575
    private function setParseC($text, &$currentMode) {
576
        $tmp = preg_quote($this->keysC, '/');
577
578
        // If we accept the ~ for special character, we must allow it.
579
        if ($this->tilde) {
580
            $tmp .= '~F';
581
        }
582
583
        $match = array();
584
        if (preg_match('/[^' . $tmp . ']/', $text, $match) === 1) {
585
            // We found something not allowed
586
            throw new BCGParseException('code128', 'The text "' . $text . '" can\'t be parsed with the Table C. The character "' . $match[0] . '" is not allowed.');
587
        } else {
588
            $latch = ($currentMode === 'C') ? '' : '2';
589
            $currentMode = 'C';
590
591
            return $latch . $this->getSequenceParsed($text, $currentMode);
592
        }
593
    }
594
595
    /**
596
     * Depending on the $text, it will return the correct
597
     * sequence to encode the text.
598
     *
599
     * @param string $text
600
     * @param string $starting_text
601
     * @return string
602
     */
603
    private function getSequence($text, &$starting_text) {
604
        $e = 10000;
605
        $latLen = array(
606
            array(0, 1, 1),
607
            array(1, 0, 1),
608
            array(1, 1, 0)
609
        );
610
        $shftLen = array(
611
            array($e, 1, $e),
612
            array(1, $e, $e),
613
            array($e, $e, $e)
614
        );
615
        $charSiz = array(2, 2, 1);
616
617
        $startA = $e;
618
        $startB = $e;
619
        $startC = $e;
620
        if ($starting_text === 'A') { $startA = 0; }
621
        if ($starting_text === 'B') { $startB = 0; }
622
        if ($starting_text === 'C') { $startC = 0; }
623
624
        $curLen = array($startA, $startB, $startC);
625
        $curSeq = array(null, null, null);
626
627
        $nextNumber = false;
628
629
        $x = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $x is dead and can be removed.
Loading history...
630
        $xLen = strlen($text);
631
        for ($x = 0; $x < $xLen; $x++) {
632
            $input = $text[$x];
633
634
            // 1.
635
            for ($i = 0; $i < 3; $i++) {
636
                for ($j = 0; $j < 3; $j++) {
637
                    if (($curLen[$i] + $latLen[$i][$j]) < $curLen[$j]) {
638
                        $curLen[$j] = $curLen[$i] + $latLen[$i][$j];
639
                        $curSeq[$j] = $curSeq[$i] . $j;
640
                    }
641
                }
642
            }
643
644
            // 2.
645
            $nxtLen = array($e, $e, $e);
646
            $nxtSeq = array();
647
648
            // 3.
649
            $flag = false;
650
            $posArray = array();
651
652
            // Special case, we do have a tilde and we process them
653
            if ($this->tilde && $input === '~') {
654
                $tildeData = self::extractTilde($text, $x);
655
656
                if ($tildeData === '~~') {
657
                    // We simply skip a tilde
658
                    $posArray[] = 1;
659
                    $x++;
660
                } elseif (substr($tildeData, 0, 2) === '~F') {
661
                    $v = intval($tildeData[2]);
662
                    $posArray[] = 0;
663
                    $posArray[] = 1;
664
                    if ($v === 1) {
665
                        $posArray[] = 2;
666
                    }
667
668
                    $x += 2;
669
                    $flag = true;
670
                }
671
            } else {
672
                $pos = strpos($this->keysA, $input);
673
                if ($pos !== false) {
674
                    $posArray[] = 0;
675
                }
676
677
                $pos = strpos($this->keysB, $input);
678
                if ($pos !== false) {
679
                    $posArray[] = 1;
680
                }
681
682
                // Do we have the next char a number?? OR a ~F1
683
                $pos = strpos($this->keysC, $input);
684
                if ($nextNumber || ($pos !== false && isset($text[$x + 1]) && strpos($this->keysC, $text[$x + 1]) !== false)) {
685
                    $nextNumber = !$nextNumber;
686
                    $posArray[] = 2;
687
                }
688
            }
689
690
            $c = count($posArray);
691
            for ($i = 0; $i < $c; $i++) {
692
                if (($curLen[$posArray[$i]] + $charSiz[$posArray[$i]]) < $nxtLen[$posArray[$i]]) {
693
                    $nxtLen[$posArray[$i]] = $curLen[$posArray[$i]] + $charSiz[$posArray[$i]];
694
                    $nxtSeq[$posArray[$i]] = $curSeq[$posArray[$i]] . '.';
695
                }
696
697
                for ($j = 0; $j < 2; $j++) {
698
                    if ($j === $posArray[$i]) { continue; }
699
                    if (($curLen[$j] + $shftLen[$j][$posArray[$i]] + $charSiz[$posArray[$i]]) < $nxtLen[$j]) {
700
                        $nxtLen[$j] = $curLen[$j] + $shftLen[$j][$posArray[$i]] + $charSiz[$posArray[$i]];
701
                        $nxtSeq[$j] = $curSeq[$j] . chr($posArray[$i] + 65) . '.';
702
                    }
703
                }
704
            }
705
706
            if ($c === 0) {
707
                // We found an unsuported character
708
                throw new BCGParseException('code128', 'Character ' .  $input . ' not supported.');
709
            }
710
711
            if ($flag) {
712
                for ($i = 0; $i < 5; $i++) {
713
                    if (isset($nxtSeq[$i])) {
714
                        $nxtSeq[$i] .= 'F';
715
                    }
716
                }
717
            }
718
719
            // 4.
720
            for ($i = 0; $i < 3; $i++) {
721
                $curLen[$i] = $nxtLen[$i];
722
                if (isset($nxtSeq[$i])) {
723
                    $curSeq[$i] = $nxtSeq[$i];
724
                }
725
            }
726
        }
727
728
        // Every curLen under $e is possible but we take the smallest
729
        $m = $e;
730
        $k = -1;
731
        for ($i = 0; $i < 3; $i++) {
732
            if ($curLen[$i] < $m) {
733
                $k = $i;
734
                $m = $curLen[$i];
735
            }
736
        }
737
738
        if ($k === -1) {
739
            return '';
740
        }
741
742
        return $curSeq[$k];
743
    }
744
745
    /**
746
     * Depending on the sequence $seq given (returned from getSequence()),
747
     * this method will return the code stream in an array. Each char will be a
748
     * string of bit based on the Code 128.
749
     *
750
     * Each letter from the sequence represents bits.
751
     *
752
     * 0 to 2 are latches
753
     * A to B are Shift + Letter
754
     * . is a char in the current encoding
755
     *
756
     * @param string $text
757
     * @param string $seq
758
     * @return string[][]
759
     */
760
    private function createBinaryStream($text, $seq) {
761
        $c = strlen($seq);
762
763
        $data = array(); // code stream
764
        $indcheck = array(); // index for checksum
765
766
        $currentEncoding = 0;
767
        if ($this->starting_text === 'A') {
768
            $currentEncoding = 0;
769
            $indcheck[] = self::KEY_STARTA;
770
            $this->lastTable = 'A';
771
        } elseif ($this->starting_text === 'B') {
772
            $currentEncoding = 1;
773
            $indcheck[] = self::KEY_STARTB;
774
            $this->lastTable = 'B';
775
        } elseif ($this->starting_text === 'C') {
776
            $currentEncoding = 2;
777
            $indcheck[] = self::KEY_STARTC;
778
            $this->lastTable = 'C';
779
        }
780
781
        $data[] = $this->code[103 + $currentEncoding];
782
783
        $temporaryEncoding = -1;
784
        for ($i = 0, $counter = 0; $i < $c; $i++) {
785
            $input = $seq[$i];
786
            $inputI = intval($input);
787
            if ($input === '.') {
788
                $this->encodeChar($data, $currentEncoding, $seq, $text, $i, $counter, $indcheck);
789
                if ($temporaryEncoding !== -1) {
790
                    $currentEncoding = $temporaryEncoding;
791
                    $temporaryEncoding = -1;
792
                }
793
            } elseif ($input >= 'A' && $input <= 'B') {
794
                // We shift
795
                $encoding = ord($input) - 65;
796
                $shift = $this->shift[$currentEncoding][$encoding];
797
                $indcheck[] = $shift;
798
                $data[] = $this->code[$shift];
799
                if ($temporaryEncoding === -1) {
800
                    $temporaryEncoding = $currentEncoding;
801
                }
802
803
                $currentEncoding = $encoding;
804
            } elseif ($inputI >= 0 && $inputI < 3) {
805
                $temporaryEncoding = -1;
806
807
                // We latch
808
                $latch = $this->latch[$currentEncoding][$inputI];
809
                if ($latch !== null) {
810
                    $indcheck[] = $latch;
811
                    $this->lastTable = chr(65 + $inputI);
812
                    $data[] = $this->code[$latch];
813
                    $currentEncoding = $inputI;
814
                }
815
            }
816
        }
817
818
        return array($indcheck, $data);
819
    }
820
821
    /**
822
     * Encodes characters, base on its encoding and sequence
823
     *
824
     * @param int[] $data
825
     * @param int $encoding
826
     * @param string $seq
827
     * @param string $text
828
     * @param int $i
829
     * @param int $counter
830
     * @param int[] $indcheck
831
     */
832
    private function encodeChar(&$data, $encoding, $seq, $text, &$i, &$counter, &$indcheck) {
833
        if (isset($seq[$i + 1]) && $seq[$i + 1] === 'F') {
834
            // We have a flag !!
835
            if ($text[$counter + 1] === 'F') {
836
                $number = $text[$counter + 2];
837
                $fnc = $this->fnc[$encoding][$number - 1];
838
                $indcheck[] = $fnc;
839
                $data[] = $this->code[$fnc];
840
841
                // Skip F + number
842
                $counter += 2;
843
            } else {
844
                // Not supposed
845
            }
846
847
            $i++;
848
        } else {
849
            if ($encoding === 2) {
850
                // We take 2 numbers in the same time
851
                $code = (int)substr($text, $counter, 2);
852
                $indcheck[] = $code;
853
                $data[] = $this->code[$code];
854
                $counter++;
855
                $i++;
856
            } else {
857
                $keys = ($encoding === 0) ? $this->keysA : $this->keysB;
858
                $pos = strpos($keys, $text[$counter]);
859
                $indcheck[] = $pos;
860
                $data[] = $this->code[$pos];
861
            }
862
        }
863
864
        $counter++;
865
    }
866
867
    /**
868
     * Saves data into the classes.
869
     *
870
     * This method will save data, calculate real column number
871
     * (if -1 was selected), the real error level (if -1 was
872
     * selected)... It will add Padding to the end and generate
873
     * the error codes.
874
     *
875
     * @param array $data
876
     */
877
    private function setData($data) {
878
        $this->indcheck = $data[0];
879
        $this->data = $data[1];
880
        $this->calculateChecksum();
881
        $this->data[] = $this->code[$this->checksumValue];
882
        $this->data[] = $this->code[self::KEY_STOP];
883
    }
884
}
885
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...