makefont.php ➔ ReadAFM()   F
last analyzed

Complexity

Conditions 30
Paths 229

Size

Total Lines 100

Duplication

Lines 2
Ratio 2 %

Importance

Changes 0
Metric Value
cc 30
nc 229
nop 2
dl 2
loc 100
rs 2.3766
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*******************************************************************************
3
* Utility to generate font definition files                                    *
4
* Version: 1.13                                                                *
5
* Date:    2004-12-31                                                          *
6
*******************************************************************************/
7
8
function ReadMap($enc)
9
{
10
	//Read a map file
11
	$file=dirname(__FILE__).'/'.strtolower($enc).'.map';
12
	$a=file($file);
13
	if(empty($a))
14
		die('<B>Error:</B> encoding not found: '.$enc);
15
	$cc2gn=array();
16
	foreach($a as $l)
17
	{
18
		if($l{0}=='!')
19
		{
20
			$e=preg_split('/[ \\t]+/',rtrim($l));
21
			$cc=hexdec(substr($e[0],1));
22
			$gn=$e[2];
23
			$cc2gn[$cc]=$gn;
24
		}
25
	}
26
	for($i=0;$i<=255;$i++)
27
	{
28
		if(!isset($cc2gn[$i]))
29
			$cc2gn[$i]='.notdef';
30
	}
31
	return $cc2gn;
32
}
33
34
function ReadAFM($file,&$map)
35
{
36
	//Read a font metric file
37
	$a=file($file);
38
	if(empty($a))
39
		die('File not found');
40
	$widths=array();
41
	$fm=array();
42
	$fix=array('Edot'=>'Edotaccent','edot'=>'edotaccent','Idot'=>'Idotaccent','Zdot'=>'Zdotaccent','zdot'=>'zdotaccent',
43
		'Odblacute'=>'Ohungarumlaut','odblacute'=>'ohungarumlaut','Udblacute'=>'Uhungarumlaut','udblacute'=>'uhungarumlaut',
44
		'Gcedilla'=>'Gcommaaccent','gcedilla'=>'gcommaaccent','Kcedilla'=>'Kcommaaccent','kcedilla'=>'kcommaaccent',
45
		'Lcedilla'=>'Lcommaaccent','lcedilla'=>'lcommaaccent','Ncedilla'=>'Ncommaaccent','ncedilla'=>'ncommaaccent',
46
		'Rcedilla'=>'Rcommaaccent','rcedilla'=>'rcommaaccent','Scedilla'=>'Scommaaccent','scedilla'=>'scommaaccent',
47
		'Tcedilla'=>'Tcommaaccent','tcedilla'=>'tcommaaccent','Dslash'=>'Dcroat','dslash'=>'dcroat','Dmacron'=>'Dcroat','dmacron'=>'dcroat',
48
		'combininggraveaccent'=>'gravecomb','combininghookabove'=>'hookabovecomb','combiningtildeaccent'=>'tildecomb',
49
		'combiningacuteaccent'=>'acutecomb','combiningdotbelow'=>'dotbelowcomb','dongsign'=>'dong');
50
	foreach($a as $l)
51
	{
52
		$e=explode(' ',rtrim($l));
53
		if(count($e)<2)
54
			continue;
55
		$code=$e[0];
56
		$param=$e[1];
57
		if($code=='C')
58
		{
59
			//Character metrics
60
			$cc=(int)$e[1];
61
			$w=$e[4];
62
			$gn=$e[7];
63
			if(substr($gn,-4)=='20AC')
64
				$gn='Euro';
65
			if(isset($fix[$gn]))
66
			{
67
				//Fix incorrect glyph name
68
				foreach($map as $c=>$n)
69
				{
70
					if($n==$fix[$gn])
71
						$map[$c]=$gn;
72
				}
73
			}
74
			if(empty($map))
75
			{
76
				//Symbolic font: use built-in encoding
77
				$widths[$cc]=$w;
78
			}
79
			else
80
			{
81
				$widths[$gn]=$w;
82
				if($gn=='X')
83
					$fm['CapXHeight']=$e[13];
84
			}
85
			if($gn=='.notdef')
86
				$fm['MissingWidth']=$w;
87
		}
88
		elseif($code=='FontName')
89
			$fm['FontName']=$param;
90
		elseif($code=='Weight')
91
			$fm['Weight']=$param;
92
		elseif($code=='ItalicAngle')
93
			$fm['ItalicAngle']=(double)$param;
94
		elseif($code=='Ascender')
95
			$fm['Ascender']=(int)$param;
96
		elseif($code=='Descender')
97
			$fm['Descender']=(int)$param;
98
		elseif($code=='UnderlineThickness')
99
			$fm['UnderlineThickness']=(int)$param;
100
		elseif($code=='UnderlinePosition')
101
			$fm['UnderlinePosition']=(int)$param;
102
		elseif($code=='IsFixedPitch')
103
			$fm['IsFixedPitch']=($param=='true');
104 View Code Duplication
		elseif($code=='FontBBox')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
105
			$fm['FontBBox']=array($e[1],$e[2],$e[3],$e[4]);
106
		elseif($code=='CapHeight')
107
			$fm['CapHeight']=(int)$param;
108
		elseif($code=='StdVW')
109
			$fm['StdVW']=(int)$param;
110
	}
111
	if(!isset($fm['FontName']))
112
		die('FontName not found');
113
	if(!empty($map))
114
	{
115
		if(!isset($widths['.notdef']))
116
			$widths['.notdef']=600;
117
		if(!isset($widths['Delta']) and isset($widths['increment']))
118
			$widths['Delta']=$widths['increment'];
119
		//Order widths according to map
120
		for($i=0;$i<=255;$i++)
121
		{
122
			if(!isset($widths[$map[$i]]))
123
			{
124
				echo '<B>Warning:</B> character '.$map[$i].' is missing<BR>';
125
				$widths[$i]=$widths['.notdef'];
126
			}
127
			else
128
				$widths[$i]=$widths[$map[$i]];
129
		}
130
	}
131
	$fm['Widths']=$widths;
132
	return $fm;
133
}
134
135
function MakeFontDescriptor($fm,$symbolic)
136
{
137
	//Ascent
138
	$asc=(isset($fm['Ascender']) ? $fm['Ascender'] : 1000);
139
	$fd="array('Ascent'=>".$asc;
140
	//Descent
141
	$desc=(isset($fm['Descender']) ? $fm['Descender'] : -200);
142
	$fd.=",'Descent'=>".$desc;
143
	//CapHeight
144 View Code Duplication
	if(isset($fm['CapHeight']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
145
		$ch=$fm['CapHeight'];
146
	elseif(isset($fm['CapXHeight']))
147
		$ch=$fm['CapXHeight'];
148
	else
149
		$ch=$asc;
150
	$fd.=",'CapHeight'=>".$ch;
151
	//Flags
152
	$flags=0;
153
	if(isset($fm['IsFixedPitch']) and $fm['IsFixedPitch'])
154
		$flags+=1<<0;
155
	if($symbolic)
156
		$flags+=1<<2;
157
	if(!$symbolic)
158
		$flags+=1<<5;
159 View Code Duplication
	if(isset($fm['ItalicAngle']) and $fm['ItalicAngle']!=0)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
160
		$flags+=1<<6;
161
	$fd.=",'Flags'=>".$flags;
162
	//FontBBox
163 View Code Duplication
	if(isset($fm['FontBBox']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
		$fbb=$fm['FontBBox'];
165
	else
166
		$fbb=array(0,$des-100,1000,$asc+100);
0 ignored issues
show
Bug introduced by
The variable $des does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
167
	$fd.=",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'";
168
	//ItalicAngle
169
	$ia=(isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0);
170
	$fd.=",'ItalicAngle'=>".$ia;
171
	//StemV
172 View Code Duplication
	if(isset($fm['StdVW']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
		$stemv=$fm['StdVW'];
174
	elseif(isset($fm['Weight']) and eregi('(bold|black)',$fm['Weight']))
175
		$stemv=120;
176
	else
177
		$stemv=70;
178
	$fd.=",'StemV'=>".$stemv;
179
	//MissingWidth
180
	if(isset($fm['MissingWidth']))
181
		$fd.=",'MissingWidth'=>".$fm['MissingWidth'];
182
	$fd.=')';
183
	return $fd;
184
}
185
186
function MakeWidthArray($fm)
187
{
188
	//Make character width array
189
	$s="array(\n\t";
190
	$cw=$fm['Widths'];
0 ignored issues
show
Unused Code introduced by
$cw is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
191
	for($i=0;$i<=255;$i++)
192
	{
193
		if(chr($i)=="'")
194
			$s.="'\\''";
195
		elseif(chr($i)=="\\")
196
			$s.="'\\\\'";
197
		elseif($i>=32 and $i<=126)
198
			$s.="'".chr($i)."'";
199
		else
200
			$s.="chr($i)";
201
		$s.='=>'.$fm['Widths'][$i];
202
		if($i<255)
203
			$s.=',';
204
		if(($i+1)%22==0)
205
			$s.="\n\t";
206
	}
207
	$s.=')';
208
	return $s;
209
}
210
211
function MakeFontEncoding($map)
212
{
213
	//Build differences from reference encoding
214
	$ref=ReadMap('cp1252');
215
	$s='';
216
	$last=0;
217
	for($i=32;$i<=255;$i++)
218
	{
219
		if($map[$i]!=$ref[$i])
220
		{
221
			if($i!=$last+1)
222
				$s.=$i.' ';
223
			$last=$i;
224
			$s.='/'.$map[$i].' ';
225
		}
226
	}
227
	return rtrim($s);
228
}
229
230 View Code Duplication
function SaveToFile($file,$s,$mode='t')
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231
{
232
	$f=fopen($file,'w'.$mode);
233
	if(!$f)
234
		die('Can\'t write to file '.$file);
235
	fwrite($f,$s,strlen($s));
236
	fclose($f);
237
}
238
239
function ReadShort($f)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
240
{
241
	$a=unpack('n1n',fread($f,2));
242
	return $a['n'];
243
}
244
245
function ReadLong($f)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
246
{
247
	$a=unpack('N1N',fread($f,4));
248
	return $a['N'];
249
}
250
251 View Code Duplication
function CheckTTF($file)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
252
{
253
	//Check if font license allows embedding
254
	$f=fopen($file,'rb');
255
	if(!$f)
256
		die('<B>Error:</B> Can\'t open '.$file);
257
	//Extract number of tables
258
	fseek($f,4,SEEK_CUR);
259
	$nb=ReadShort($f);
260
	fseek($f,6,SEEK_CUR);
261
	//Seek OS/2 table
262
	$found=false;
263
	for($i=0;$i<$nb;$i++)
264
	{
265
		if(fread($f,4)=='OS/2')
266
		{
267
			$found=true;
268
			break;
269
		}
270
		fseek($f,12,SEEK_CUR);
271
	}
272
	if(!$found)
273
	{
274
		fclose($f);
275
		return;
276
	}
277
	fseek($f,4,SEEK_CUR);
278
	$offset=ReadLong($f);
279
	fseek($f,$offset,SEEK_SET);
280
	//Extract fsType flags
281
	fseek($f,8,SEEK_CUR);
282
	$fsType=ReadShort($f);
283
	$rl=($fsType & 0x02)!=0;
284
	$pp=($fsType & 0x04)!=0;
285
	$e=($fsType & 0x08)!=0;
286
	fclose($f);
287
	if($rl and !$pp and !$e)
288
		echo '<B>Warning:</B> font license does not allow embedding';
289
}
290
291
/*******************************************************************************
292
* $fontfile : chemin du fichier TTF (ou cha�ne vide si pas d'incorporation)    *
293
* $afmfile :  chemin du fichier AFM                                            *
294
* $enc :      encodage (ou cha�ne vide si la police est symbolique)            *
295
* $patch :    patch optionnel pour l'encodage                                  *
296
* $type :     type de la police si $fontfile est vide                          *
297
*******************************************************************************/
298
function MakeFont($fontfile,$afmfile,$enc='cp1252',$patch=array(),$type='TrueType')
299
{
300
	//Generate a font definition file
301
	set_magic_quotes_runtime(0);
302
	ini_set('auto_detect_line_endings','1');
303
	if($enc)
304
	{
305
		$map=ReadMap($enc);
306
		foreach($patch as $cc=>$gn)
307
			$map[$cc]=$gn;
308
	}
309
	else
310
		$map=array();
311
	if(!file_exists($afmfile))
312
		die('<B>Error:</B> AFM file not found: '.$afmfile);
313
	$fm=ReadAFM($afmfile,$map);
314
	if($enc)
315
		$diff=MakeFontEncoding($map);
316
	else
317
		$diff='';
318
	$fd=MakeFontDescriptor($fm,empty($map));
319
	//Find font type
320
	if($fontfile)
321
	{
322
		$ext=strtolower(substr($fontfile,-3));
323
		if($ext=='ttf')
324
			$type='TrueType';
325
		elseif($ext=='pfb')
326
			$type='Type1';
327
		else
328
			die('<B>Error:</B> unrecognized font file extension: '.$ext);
329
	}
330
	else
331
	{
332
		if($type!='TrueType' and $type!='Type1')
333
			die('<B>Error:</B> incorrect font type: '.$type);
334
	}
335
	//Start generation
336
	$s='<?php'."\n";
337
	$s.='$type=\''.$type."';\n";
338
	$s.='$name=\''.$fm['FontName']."';\n";
339
	$s.='$desc='.$fd.";\n";
340
	if(!isset($fm['UnderlinePosition']))
341
		$fm['UnderlinePosition']=-100;
342
	if(!isset($fm['UnderlineThickness']))
343
		$fm['UnderlineThickness']=50;
344
	$s.='$up='.$fm['UnderlinePosition'].";\n";
345
	$s.='$ut='.$fm['UnderlineThickness'].";\n";
346
	$w=MakeWidthArray($fm);
347
	$s.='$cw='.$w.";\n";
348
	$s.='$enc=\''.$enc."';\n";
349
	$s.='$diff=\''.$diff."';\n";
350
	$basename=substr(basename($afmfile),0,-4);
351
	if($fontfile)
352
	{
353
		//Embedded font
354
		if(!file_exists($fontfile))
355
			die('<B>Error:</B> font file not found: '.$fontfile);
356
		if($type=='TrueType')
357
			CheckTTF($fontfile);
358
		$f=fopen($fontfile,'rb');
359
		if(!$f)
360
			die('<B>Error:</B> Can\'t open '.$fontfile);
361
		$file=fread($f,filesize($fontfile));
362
		fclose($f);
363
		if($type=='Type1')
364
		{
365
			//Find first two sections and discard third one
366
			$header=(ord($file{0})==128);
367
			if($header)
368
			{
369
				//Strip first binary header
370
				$file=substr($file,6);
371
			}
372
			$pos=strpos($file,'eexec');
373
			if(!$pos)
374
				die('<B>Error:</B> font file does not seem to be valid Type1');
375
			$size1=$pos+6;
376
			if($header and ord($file{$size1})==128)
377
			{
378
				//Strip second binary header
379
				$file=substr($file,0,$size1).substr($file,$size1+6);
380
			}
381
			$pos=strpos($file,'00000000');
382
			if(!$pos)
383
				die('<B>Error:</B> font file does not seem to be valid Type1');
384
			$size2=$pos-$size1;
385
			$file=substr($file,0,$size1+$size2);
386
		}
387
		if(function_exists('gzcompress'))
388
		{
389
			$cmp=$basename.'.z';
390
			SaveToFile($cmp,gzcompress($file),'b');
391
			$s.='$file=\''.$cmp."';\n";
392
			echo 'Font file compressed ('.$cmp.')<BR>';
393
		}
394
		else
395
		{
396
			$s.='$file=\''.basename($fontfile)."';\n";
397
			echo '<B>Notice:</B> font file could not be compressed (zlib extension not available)<BR>';
398
		}
399 View Code Duplication
		if($type=='Type1')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
400
		{
401
			$s.='$size1='.$size1.";\n";
0 ignored issues
show
Bug introduced by
The variable $size1 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
402
			$s.='$size2='.$size2.";\n";
0 ignored issues
show
Bug introduced by
The variable $size2 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
403
		}
404
		else
405
			$s.='$originalsize='.filesize($fontfile).";\n";
406
	}
407
	else
408
	{
409
		//Not embedded font
410
		$s.='$file='."'';\n";
411
	}
412
	$s.="?>\n";
413
	SaveToFile($basename.'.php',$s);
414
	echo 'Font definition file generated ('.$basename.'.php'.')<BR>';
415
}
416
?>
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...
417