1# text2pdf.pl - simple PDFJ sample script
2# 2004 <nakajima@netstock.co.jp>
3# perl text2pdf.pl INFILE OUTFILE
4
5use PDFJ 'EUC';
6
7use Getopt::Std;
8use strict;
9
10my @KutenEUC = ("\xa1\xa3", "\xa1\xa5", "\xa1\xa2", "\xa1\xa4");
11
12my %Opt;
13getopts 'sec:', \%Opt;
14my($InFile, $OutFile) = @ARGV;
15$OutFile ||= "$InFile.pdf";
16
17my %Cfg;
18readcfgfile("$0.cfg", \%Cfg);
19readcfgfile($Opt{c}, \%Cfg) if $Opt{c};
20
21my $TextCode =
22	$Opt{s} ? 'SJIS' :
23	$Opt{e} ? 'EUC' :
24	$Cfg{TextCode};
25
26my $Encoding = $PDFJ::Default{Jcode} eq 'SJIS' ? $Cfg{EncodingSJIS} : $Cfg{EncodingEUC};
27my $Linewidth = $Cfg{Pagesize}[0] - $Cfg{Margin}[0] - $Cfg{Margin}[1];
28my $PageHeight = $Cfg{Pagesize}[1] - $Cfg{Margin}[2] - $Cfg{Margin}[3];
29my @PosBody = ($Cfg{Margin}[0], $Cfg{Pagesize}[1] - $Cfg{Margin}[3]);
30my @PosHeader = ($Cfg{Margin}[0], $Cfg{Pagesize}[1] - $Cfg{Margin}[3] +
31	$Cfg{Margin}[2] / 2);
32my @PosFooter = ($Cfg{Margin}[0], $Cfg{Margin}[3] / 2);
33my $Time = scalar(localtime);
34
35my(%Font, %TStyle, %PStyle, %Sptn);
36
37my $Doc = PDFJ::Doc->new(1.2, @{$Cfg{Pagesize}});
38
39for my $name(qw(Body Fixed Header Footer)) {
40	setparaspec($name, $Cfg{"${name}Spec"});
41}
42for my $name(qw(Subtitle1 Subtitle2 Subtitle3 Subtitle4)) {
43	setparaspec($name, $Cfg{"${name}Spec"}, 1);
44}
45for( my $j = 1; $j <= $Cfg{Titles}; $j++ ) {
46	my $name = "Title$j";
47	setparaspec($name, $Cfg{"${name}Spec"});
48}
49if( ref($Cfg{SpecialTitleSpec}) eq 'HASH' ) {
50	my $sptnnum = 0;
51	for my $ptn(keys %{$Cfg{SpecialTitleSpec}}) {
52		$Sptn{$ptn} = $sptnnum;
53		setparaspec("Special$sptnnum", $Cfg{SpecialTitleSpec}{$ptn});
54		$sptnnum++;
55	}
56}
57my $BodyLineFeed = $PStyle{Body}{linefeed};
58if( $BodyLineFeed =~ /^(\d+)%/ ) {
59	$BodyLineFeed = $TStyle{Body}{fontsize} * $1 / 100;
60}
61
62my $EmptyLineSkip = $Cfg{EmptyLineSkip} || $BodyLineFeed;
63
64my @tmp;
65open F, $InFile or die;
66while(<F>) {
67	s/\r\n/\n/;
68	chomp;
69	if( $TextCode eq 'SJIS' ) {
70		$_ = sjis2euc($_);
71	}
72	if( /^\s*$/ ) {
73		if( @tmp ) {
74			if( ref($tmp[$#tmp]) eq 'T2P::Empty' ) {
75				${$tmp[$#tmp]}++;
76			} else {
77				my $work = 1;
78				push @tmp, bless(\$work, 'T2P::Empty');
79			}
80		}
81	} elsif( /^\S/ && /\S$/ && !/  / &&
82		(!@tmp || ref($tmp[$#tmp]) eq 'T2P::Empty' ||
83		ref($tmp[$#tmp]) eq 'T2P::Title') &&
84		length($_) <= $Cfg{TitleMaxlen} && !lastiskuten($_) ) {
85		if( @tmp && ref($tmp[$#tmp]) eq 'T2P::Title' ) {
86			if( islabeled($_) ) {
87				my $last = pop @tmp;
88				push @tmp, @$last;
89				push @tmp, $_;
90			} else {
91				push @{$tmp[$#tmp]}, $_;
92			}
93		} else {
94			push @tmp, bless([$_], 'T2P::Title');
95		}
96	} else {
97		if( @tmp && ref($tmp[$#tmp]) eq 'T2P::Title' ) {
98			my $last = pop @tmp;
99			push @tmp, @$last;
100		}
101		push @tmp, $_;
102	}
103}
104close F;
105
106my @objects;
107my $titles = 0;
108for( my $j = 0; $j < @tmp; $j++ ) {
109	local($_) = $tmp[$j];
110	if( ref($_) eq 'T2P::Empty' ) {
111		if( $j > 0 && !ref($tmp[$j - 1]) && $j < $#tmp && !ref($tmp[$j + 1]) ) {
112			push @objects, BlockSkip($EmptyLineSkip * $$_);
113		}
114	} elsif( ref($_) eq 'T2P::Title' ) {
115		my $ttxt = join("\n", @$_);
116		my $special = 0;
117		for my $ptn(keys %Sptn) {
118			if( $ttxt =~ /$ptn/s ) {
119				push @objects, para("Special$Sptn{$ptn}", 0, 0, @$_);
120				$special = 1;
121				last;
122			}
123		}
124		next if $special;
125		$titles++;
126		if( $titles <= $Cfg{Titles} ) {
127			push @objects, para("Title$titles", 0, 0, @$_);
128		} else {
129			my $num = 1;
130			if( ref($tmp[$j - 1]) eq 'T2P::Empty' ) {
131				$num = ${$tmp[$j - 1]};
132				$num = 4 if $num > 4;
133			}
134			push @objects, para("Subtitle$num", 0, 0, @$_);
135		}
136	} else {
137		my $fixed = /^ /;
138		$_ = expandtab($_, $Cfg{Tabwidth});
139		my $indent = 0;
140		if( s/^ +// ) {
141			$indent = $TStyle{Body}{fontsize} / 2 * length($&);
142		}
143		my $paraname = $fixed ? "Fixed" : "Body";
144		push @objects, para($paraname, 0, $indent, $_);
145	}
146}
147
148for my $block( Block('V', \@objects, BStyle())->break($PageHeight) ) {
149	my $page = $Doc->new_page;
150	print "page ",$page->pagenum,"\n";
151	$block->show($page, @PosBody);
152	my $htext = $Cfg{Header};
153	my $header = Paragraph(Text(headerfooter($page, $Cfg{Header}),
154		$TStyle{Header}), $PStyle{Header});
155	$header->show($page, @PosHeader);
156	my $footer = Paragraph(Text(headerfooter($page, $Cfg{Footer}),
157		$TStyle{Footer}), $PStyle{Footer});
158	$footer->show($page, @PosFooter);
159}
160$Doc->print($OutFile);
161
162sub islabeled {
163	local($_) = @_;
164	for my $mark(@{$Cfg{ItemMark}}) {
165		if( s/^\Q$mark\E// ) {
166			return 1;
167		}
168	}
169	for my $ptn(@{$Cfg{EnumPattern}}) {
170		if( s/^$ptn// ) {
171			return 1;
172		}
173	}
174	if( /\t/ ) {
175		return 1;
176	}
177	0;
178}
179
180sub picklabel {
181	local($_) = @_;
182	my $label = '';
183	my($labelsize, $labelskip) = (0, 0);
184	for my $mark(@{$Cfg{ItemMark}}) {
185		if( s/^\Q$mark\E// ) {
186			$label = $mark;
187			return ($label, $_, @{$Cfg{ItemLabelspec}});
188		}
189	}
190	for my $ptn(@{$Cfg{EnumPattern}}) {
191		if( s/^$ptn// ) {
192			$label = $&;
193			return ($label, $_, @{$Cfg{EnumLabelspec}});
194		}
195	}
196	if( /\t/ ) {
197		return ($`, $', @{$Cfg{DescLabelspec}});
198	}
199	($label, $_, $labelsize, $labelskip);
200}
201
202sub expandtab {
203	my($str, $tabwidth) = @_;
204	while( $str =~ s/^( *)\t/$1.(' ' x ($tabwidth - length($1) % $tabwidth))/e )
205		{}
206	$str;
207}
208
209sub _para {
210	my($pstyle, $tstyle, $size, $indent, $label, $labelsize, $labelskip, @texts)
211		= @_;
212	if( $size ) {
213		$pstyle = $pstyle->clone(size => $size, beginpadding => 0);
214	}
215	if( $indent ) {
216		$pstyle = $pstyle->clone(beginpadding =>
217			$pstyle->{beginpadding} + $indent);
218	}
219	if( $label ne '' ) {
220		$pstyle = $pstyle->clone(labeltext => $label, labelsize => $labelsize,
221			labelskip => $labelskip);
222	}
223	Paragraph(Text(\@texts, $tstyle), $pstyle);
224}
225
226sub para {
227	my($name, $size, $indent, @texts) = @_;
228	die "missing texts for paragraph" unless @texts;
229	my($label, $labelsize, $labelskip);
230	($label, $texts[0], $labelsize, $labelskip) = picklabel($texts[0]);
231	for( my $j = 0; $j < @texts - 1; $j += 2 ) {
232		splice @texts, $j + 1, 0, NewLine;
233	}
234	if( $name eq 'Fixed' ) {
235		@texts = map {ref($_) ? $_ : space2hankaku($_)} @texts;
236	}
237	my $pstyle = $PStyle{$name};
238	my $tstyle = $TStyle{$name};
239	die "missing Spec for '$name'" unless $pstyle && $tstyle;
240	if( $name eq 'Fixed' ) {
241		$tstyle->{noglue} = 1;
242		$tstyle->{noshift} = 1;
243	}
244	_para($pstyle, $tstyle, $size, $indent, $label, $labelsize, $labelskip,
245		@texts);
246}
247
248sub space2hankaku {
249	my($str) = @_;
250	my @result;
251	while( $str =~ / +/ ) {
252		$str = $';
253		push @result, $` if $` ne '';
254		push @result, Space($Cfg{FixedSpec}[2] / 2 * length($&));
255	}
256	push @result, $str if $str ne '';
257	@result;
258}
259
260sub setparaspec {
261	my($name, $spec, $postnobreak) = @_;
262	$Font{$name} = $spec->[1] ?
263		$Doc->new_font($spec->[0], $Encoding, $spec->[1], 'WinAnsiEncoding',
264		1.05) :
265		$Doc->new_font($spec->[0], $Encoding);
266	$TStyle{$name} = TStyle(font => $Font{$name}, fontsize => $spec->[2]);
267	my $indent = $spec->[5] * $TStyle{$name}{fontsize} / 2;
268	$PStyle{$name} = defined $spec->[6] ?
269		PStyle(size => $Linewidth, linefeed => $spec->[3],
270		align => $spec->[4], beginpadding => $indent,
271		preskip => $spec->[6], postskip => $spec->[7]) :
272		PStyle(size => $Linewidth, linefeed => $spec->[3],
273		align => $spec->[4], beginpadding => $indent);
274	$PStyle{$name}{postnobreak} = 1 if $postnobreak;
275}
276
277sub headerfooter {
278	my($page, $spec) = @_;
279	$spec =~ s/%t/$Time/g;
280	$spec =~ s/%f/$InFile/g;
281	$spec =~ s/%p/$page->pagenum/ge;
282	$spec;
283}
284
285# cfgfile must be EUC
286sub readcfgfile {
287	my($cfgfile, $cfg) = @_;
288	my($invalue, $endmark, $key, $value);
289	my $F = new FileHandle;
290
291	open $F, $cfgfile or die "cannot open $cfgfile";
292	$invalue = 0;
293	while(<$F>) {
294		s/\r\n/\n/;
295		if( $invalue ) {
296			if( /^$endmark$/ ) {
297				$invalue = 0;
298			} else {
299				$cfg->{$key} .= $_;
300			}
301		} elsif( /^(\w+)\s*=\s*(.+)/ ) {
302			$key = $1;
303			$value = $2;
304			if( $value =~ /^<<(.+)/ ) {
305				$endmark = $1;
306				$invalue = 1;
307			} else {
308				$cfg->{$key} = $value;
309			}
310		}
311	}
312	close($F);
313	for my $key(keys %$cfg) {
314		my $value = $cfg->{$key};
315		if( $value =~ /^\"/ && $value =~ /\"\s*$/ ) {
316			$value =~ s/^\"//;
317			$value =~ s/\"\s*$//;
318		} elsif( $value =~ /^\[/ && $value =~ /\]\s*$/ ) {
319			$value = eval($value);
320		} elsif( $value =~ /^\{/ && $value =~ /\}\s*$/ ) {
321			$value = eval($value);
322		}
323		$cfg->{$key} = $value;
324	}
325}
326
327# no I18N::Japanese; for jperl
328BEGIN {
329	eval { require I18N::Japanese; };
330	I18N::Japanese->unimport() unless($@);
331}
332
333# use bytes for Perl5.8
334BEGIN {
335	eval { require bytes; };
336	bytes->import unless $@;
337}
338
339sub lastiskuten {
340	&lastiskuten_EUC;
341}
342
343sub lastiskuten_EUC {
344	my($str) = @_;
345	my @c = split('', $str);
346	my $lastiskuten = 0;
347	for( my $j = 0; $j <= $#c; $j++ ) {
348		my $c = $c[$j];
349		$lastiskuten = 0;
350		if( $c eq "\x8e" ) {
351			$j++;
352		} elsif( $c eq "\x8f" ) {
353			$j += 2;
354		} elsif( $c lt "\xa0" ) {
355		} else {
356			my $k = $c.$c[$j+1];
357			$j++;
358			$lastiskuten = 1 if grep {$_ eq $k} @KutenEUC;
359		}
360	}
361	$lastiskuten;
362}
363
364my %extin = (
365"\xFA\xAF" => "\xED\x93",
366"\xFB\xE9" => "\xEE\xCD",
367"\xFA\xEC" => "\xED\xD0",
368"\xFB\x79" => "\xEE\x5D",
369"\xFA\xF2" => "\xED\xD6",
370"\xFA\xF3" => "\xED\xD7",
371"\xFA\x8F" => "\xED\x72",
372"\xFC\x4B" => "\xEE\xEC",
373"\xFB\x7C" => "\xEE\x60",
374"\xFA\xBD" => "\xED\xA1",
375"\xFA\xB4" => "\xED\x98",
376"\xFA\xB5" => "\xED\x99",
377"\xFC\x48" => "\xEE\xE9",
378"\xFB\x59" => "\xED\xFA",
379"\xFA\xE9" => "\xED\xCD",
380"\xFA\xFA" => "\xED\xDE",
381"\xFA\xBE" => "\xED\xA2",
382"\xFA\x81" => "\xED\x64",
383"\xFC\x47" => "\xEE\xE8",
384"\xFB\x73" => "\xEE\x57",
385"\xFB\x71" => "\xEE\x55",
386"\xFB\x72" => "\xEE\x56",
387"\xFA\xEE" => "\xED\xD2",
388"\xFB\x56" => "\xED\xF7",
389"\xFA\xF4" => "\xED\xD8",
390"\xFB\x57" => "\xED\xF8",
391"\xFB\x7A" => "\xEE\x5E",
392"\xFB\xA3" => "\xEE\x87",
393"\xFB\x5B" => "\xED\xFC",
394"\xFA\xB2" => "\xED\x96",
395"\xFA\xF0" => "\xED\xD4",
396"\xFA\x5D" => "\xED\x41",
397"\xFA\x6D" => "\xED\x51",
398"\xFB\x84" => "\xEE\x67",
399"\xFA\xB6" => "\xED\x9A",
400"\xFA\x69" => "\xED\x4D",
401"\xFB\x5C" => "\xEE\x40",
402"\xFB\xA6" => "\xEE\x8A",
403"\xFA\x8C" => "\xED\x6F",
404"\xFA\xF5" => "\xED\xD9",
405"\xFA\xF1" => "\xED\xD5",
406"\xFA\xAE" => "\xED\x92",
407"\xFB\xED" => "\xEE\xD1",
408"\xFA\x61" => "\xED\x45",
409"\xFB\x41" => "\xED\xE2",
410"\xFB\x55" => "\xED\xF6",
411"\xFA\xB0" => "\xED\x94",
412"\xFA\x73" => "\xED\x57",
413"\xFA\x85" => "\xED\x68",
414"\xFB\xEE" => "\xEE\xD2",
415"\xFB\x7B" => "\xEE\x5F",
416"\xFB\x5D" => "\xEE\x41",
417"\xFB\x65" => "\xEE\x49",
418"\xFB\x85" => "\xEE\x68",
419"\xFB\x51" => "\xED\xF2",
420"\xFB\xEF" => "\xEE\xD3",
421"\xFA\xC6" => "\xED\xAA",
422"\xFA\xF9" => "\xED\xDD",
423"\xFA\xB7" => "\xED\x9B",
424"\xFB\x87" => "\xEE\x6A",
425"\xFB\xA7" => "\xEE\x8B",
426"\xFA\xEB" => "\xED\xCF",
427"\xFA\x6A" => "\xED\x4E",
428"\xFB\xA4" => "\xEE\x88",
429"\xFA\x6E" => "\xED\x52",
430"\xFB\xF0" => "\xEE\xD4",
431"\xFB\xF1" => "\xEE\xD5",
432"\xFB\x93" => "\xEE\x76",
433"\xFA\xCE" => "\xED\xB2",
434"\xFB\xB8" => "\xEE\x9C",
435"\xFB\x60" => "\xEE\x44",
436"\xFA\xF6" => "\xED\xDA",
437"\xFA\xCC" => "\xED\xB0",
438"\xFB\x5A" => "\xED\xFB",
439"\xFA\xB3" => "\xED\x97",
440"\xFA\x8D" => "\xED\x70",
441"\xFA\xBA" => "\xED\x9E",
442"\xFA\x94" => "\xED\x77",
443"\xFA\xD1" => "\xED\xB5",
444"\xFB\xF2" => "\xEE\xD6",
445"\xFB\xE8" => "\xEE\xCC",
446"\xFB\xF3" => "\xEE\xD7",
447"\xFA\xB8" => "\xED\x9C",
448"\xFB\x42" => "\xED\xE3",
449"\xFB\x48" => "\xED\xE9",
450"\xFA\xC9" => "\xED\xAD",
451"\xFB\x61" => "\xEE\x45",
452"\xFA\x40" => "\xEE\xEF",
453"\xFA\x41" => "\xEE\xF0",
454"\xFB\xA2" => "\xEE\x86",
455"\xFA\x42" => "\xEE\xF1",
456"\xFB\x8D" => "\xEE\x70",
457"\xFA\x43" => "\xEE\xF2",
458"\xFB\x6E" => "\xEE\x52",
459"\xFA\x57" => "\xEE\xFC",
460"\xFA\x44" => "\xEE\xF3",
461"\xFA\x45" => "\xEE\xF4",
462"\xFA\x46" => "\xEE\xF5",
463"\xFA\x98" => "\xED\x7B",
464"\xFA\x47" => "\xEE\xF6",
465"\xFB\xC1" => "\xEE\xA5",
466"\xFA\x48" => "\xEE\xF7",
467"\xFA\xCF" => "\xED\xB3",
468"\xFA\x56" => "\xEE\xFB",
469"\xFA\x49" => "\xEE\xF8",
470"\xFB\xB9" => "\xEE\x9D",
471"\xFB\x67" => "\xEE\x4B",
472"\xFA\xF8" => "\xED\xDC",
473"\xFB\x69" => "\xEE\x4D",
474"\xFB\xF8" => "\xEE\xDC",
475"\xFB\xC3" => "\xEE\xA7",
476"\xFA\xDB" => "\xED\xBF",
477"\xFB\x68" => "\xEE\x4C",
478"\xFB\x64" => "\xEE\x48",
479"\xFB\x6A" => "\xEE\x4E",
480"\xFA\x92" => "\xED\x75",
481"\xFA\xD3" => "\xED\xB7",
482"\xFB\xA8" => "\xEE\x8C",
483"\xFB\x4A" => "\xED\xEB",
484"\xFB\x62" => "\xEE\x46",
485"\xFA\x67" => "\xED\x4B",
486"\xFA\x76" => "\xED\x5A",
487"\xFB\x46" => "\xED\xE7",
488"\xFB\xC2" => "\xEE\xA6",
489"\xFA\xCA" => "\xED\xAE",
490"\xFB\x49" => "\xED\xEA",
491"\xFB\xB6" => "\xEE\x9A",
492"\xFA\xD4" => "\xED\xB8",
493"\xFB\x8C" => "\xEE\x6F",
494"\xFA\x77" => "\xED\x5B",
495"\xFB\xF4" => "\xEE\xD8",
496"\xFB\x81" => "\xEE\x64",
497"\xFA\xDC" => "\xED\xC0",
498"\xFB\x63" => "\xEE\x47",
499"\xFA\xDF" => "\xED\xC3",
500"\xFB\xCC" => "\xEE\xB0",
501"\xFA\xD2" => "\xED\xB6",
502"\xFA\xBB" => "\xED\x9F",
503"\xFA\xCD" => "\xED\xB1",
504"\xFA\x91" => "\xED\x74",
505"\xFA\x9A" => "\xED\x7D",
506"\xFA\xF7" => "\xED\xDB",
507"\xFA\x99" => "\xED\x7C",
508"\xFA\x75" => "\xED\x59",
509"\xFB\x83" => "\xEE\x66",
510"\xFB\xEB" => "\xEE\xCF",
511"\xFB\xDE" => "\xEE\xC2",
512"\xFA\x63" => "\xED\x47",
513"\xFB\x44" => "\xED\xE5",
514"\xFB\x4C" => "\xED\xED",
515"\xFA\x70" => "\xED\x54",
516"\xFA\xDD" => "\xED\xC1",
517"\xFB\xAA" => "\xEE\x8E",
518"\xFB\xB5" => "\xEE\x99",
519"\xFA\xFC" => "\xED\xE0",
520"\xFB\x43" => "\xED\xE4",
521"\xFA\x95" => "\xED\x78",
522"\xFC\x46" => "\xEE\xE7",
523"\xFB\xF5" => "\xEE\xD9",
524"\xFB\xAF" => "\xEE\x93",
525"\xFA\x9F" => "\xED\x83",
526"\xFA\x9E" => "\xED\x82",
527"\xFA\xD0" => "\xED\xB4",
528"\xFB\xAB" => "\xEE\x8F",
529"\xFB\x45" => "\xED\xE6",
530"\xFA\xA8" => "\xED\x8C",
531"\xFB\xBB" => "\xEE\x9F",
532"\xFA\x6F" => "\xED\x53",
533"\xFB\x66" => "\xEE\x4A",
534"\xFB\x96" => "\xEE\x79",
535"\xFA\x72" => "\xED\x56",
536"\xFB\x8A" => "\xEE\x6D",
537"\xFA\xB9" => "\xED\x9D",
538"\xFB\xA5" => "\xEE\x89",
539"\xFC\x44" => "\xEE\xE5",
540"\xFB\xBA" => "\xEE\x9E",
541"\xFA\xE5" => "\xED\xC9",
542"\xFB\xFB" => "\xEE\xDF",
543"\xFB\xBC" => "\xEE\xA0",
544"\xFB\x47" => "\xED\xE8",
545"\xFA\x71" => "\xED\x55",
546"\xFB\x8E" => "\xEE\x71",
547"\xFB\xFC" => "\xEE\xE0",
548"\xFB\xCA" => "\xEE\xAE",
549"\xFB\x5F" => "\xEE\x43",
550"\xFA\x96" => "\xED\x79",
551"\xFC\x45" => "\xEE\xE6",
552"\xFB\xC4" => "\xEE\xA8",
553"\xFC\x40" => "\xEE\xE1",
554"\xFB\xE1" => "\xEE\xC5",
555"\xFB\xDD" => "\xEE\xC1",
556"\xFB\xC6" => "\xEE\xAA",
557"\xFB\xDB" => "\xEE\xBF",
558"\xFB\x99" => "\xEE\x7C",
559"\xFB\xBF" => "\xEE\xA3",
560"\xFA\xA4" => "\xED\x88",
561"\xFB\xC0" => "\xEE\xA4",
562"\xFB\x74" => "\xEE\x58",
563"\xFA\x74" => "\xED\x58",
564"\xFA\xFB" => "\xED\xDF",
565"\xFA\x7A" => "\xED\x5E",
566"\xFB\xD8" => "\xEE\xBC",
567"\xFB\xC5" => "\xEE\xA9",
568"\xFA\x78" => "\xED\x5C",
569"\xFB\x91" => "\xEE\x74",
570"\xFA\xE2" => "\xED\xC6",
571"\xFB\xD7" => "\xEE\xBB",
572"\xFB\xBD" => "\xEE\xA1",
573"\xFB\x6B" => "\xEE\x4F",
574"\xFB\x8B" => "\xEE\x6E",
575"\xFB\xBE" => "\xEE\xA2",
576"\xFA\x97" => "\xED\x7A",
577"\xFB\x88" => "\xEE\x6B",
578"\xFA\xD6" => "\xED\xBA",
579"\xFA\xD7" => "\xED\xBB",
580"\xFB\xD2" => "\xEE\xB6",
581"\xFA\xE4" => "\xED\xC8",
582"\xFA\x7D" => "\xED\x61",
583"\xFB\xD6" => "\xEE\xBA",
584"\xFB\xD4" => "\xEE\xB8",
585"\xFB\xC7" => "\xEE\xAB",
586"\xFB\xD0" => "\xEE\xB4",
587"\xFA\xCB" => "\xED\xAF",
588"\xFB\xD1" => "\xEE\xB5",
589"\xFB\x40" => "\xED\xE1",
590"\xFA\x84" => "\xED\x67",
591"\xFA\x82" => "\xED\x65",
592"\xFB\xC9" => "\xEE\xAD",
593"\xFA\xA5" => "\xED\x89",
594"\xFB\x94" => "\xEE\x77",
595"\xFB\xAC" => "\xEE\x90",
596"\xFA\xD5" => "\xED\xB9",
597"\xFB\x98" => "\xEE\x7B",
598"\xFB\xC8" => "\xEE\xAC",
599"\xFA\x86" => "\xED\x69",
600"\xFB\x9E" => "\xEE\x82",
601"\xFB\xD5" => "\xEE\xB9",
602"\xFB\x8F" => "\xEE\x72",
603"\xFA\x55" => "\xEE\xFA",
604"\xFB\xE2" => "\xEE\xC6",
605"\xFB\xCF" => "\xEE\xB3",
606"\xFB\x97" => "\xEE\x7A",
607"\xFA\x89" => "\xED\x6C",
608"\xFA\xC3" => "\xED\xA7",
609"\xFB\x4E" => "\xED\xEF",
610"\xFB\x4F" => "\xED\xF0",
611"\xFB\x77" => "\xEE\x5B",
612"\xFA\x8A" => "\xED\x6D",
613"\xFB\xAD" => "\xEE\x91",
614"\xFA\x60" => "\xED\x44",
615"\xFA\xDE" => "\xED\xC2",
616"\xFA\x66" => "\xED\x4A",
617"\xFB\xAE" => "\xEE\x92",
618"\xFA\xD9" => "\xED\xBD",
619"\xFB\x4D" => "\xED\xEE",
620"\xFB\xCB" => "\xEE\xAF",
621"\xFA\x5E" => "\xED\x42",
622"\xFA\x7E" => "\xED\x62",
623"\xFA\x90" => "\xED\x73",
624"\xFB\x6C" => "\xEE\x50",
625"\xFA\x9B" => "\xED\x7E",
626"\xFA\x7C" => "\xED\x60",
627"\xFA\x9C" => "\xED\x80",
628"\xFB\x6F" => "\xEE\x53",
629"\xFB\x90" => "\xEE\x73",
630"\xFB\x95" => "\xEE\x78",
631"\xFA\xC1" => "\xED\xA5",
632"\xFA\xB1" => "\xED\x95",
633"\xFA\x64" => "\xED\x48",
634"\xFA\xD8" => "\xED\xBC",
635"\xFA\x65" => "\xED\x49",
636"\xFA\xE8" => "\xED\xCC",
637"\xFA\x79" => "\xED\x5D",
638"\xFA\xEA" => "\xED\xCE",
639"\xFB\x58" => "\xED\xF9",
640"\xFB\x5E" => "\xEE\x42",
641"\xFB\x75" => "\xEE\x59",
642"\xFB\x7D" => "\xEE\x61",
643"\xFB\xE5" => "\xEE\xC9",
644"\xFB\x7E" => "\xEE\x62",
645"\xFB\xD9" => "\xEE\xBD",
646"\xFB\xE3" => "\xEE\xC7",
647"\xFA\xA0" => "\xED\x84",
648"\xFA\xE6" => "\xED\xCA",
649"\xFB\xDC" => "\xEE\xC0",
650"\xFA\xE7" => "\xED\xCB",
651"\xFB\xE0" => "\xEE\xC4",
652"\xFB\xCD" => "\xEE\xB1",
653"\xFA\xE1" => "\xED\xC5",
654"\xFB\x80" => "\xEE\x63",
655"\xFB\xCE" => "\xEE\xB2",
656"\xFA\x87" => "\xED\x6A",
657"\xFB\x82" => "\xEE\x65",
658"\xFB\x86" => "\xEE\x69",
659"\xFB\x89" => "\xEE\x6C",
660"\xFB\x92" => "\xEE\x75",
661"\xFB\x9D" => "\xEE\x81",
662"\xFA\xC0" => "\xED\xA4",
663"\xFC\x42" => "\xEE\xE3",
664"\xFA\xA1" => "\xED\x85",
665"\xFB\xB2" => "\xEE\x96",
666"\xFC\x41" => "\xEE\xE2",
667"\xFA\xA2" => "\xED\x86",
668"\xFC\x4A" => "\xEE\xEB",
669"\xFB\x9F" => "\xEE\x83",
670"\xFB\xA0" => "\xEE\x84",
671"\xFA\xC5" => "\xED\xA9",
672"\xFA\xA7" => "\xED\x8B",
673"\xFA\xE0" => "\xED\xC4",
674"\xFB\x52" => "\xED\xF3",
675"\xFB\x6D" => "\xEE\x51",
676"\xFB\xA9" => "\xEE\x8D",
677"\xFB\xB1" => "\xEE\x95",
678"\xFA\xC7" => "\xED\xAB",
679"\xFB\x4B" => "\xED\xEC",
680"\xFB\x54" => "\xED\xF5",
681"\xFB\xB3" => "\xEE\x97",
682"\xFB\xB4" => "\xEE\x98",
683"\xFA\xAB" => "\xED\x8F",
684"\xFA\x8B" => "\xED\x6E",
685"\xFA\x83" => "\xED\x66",
686"\xFB\xB7" => "\xEE\x9B",
687"\xFA\xBF" => "\xED\xA3",
688"\xFA\xAC" => "\xED\x90",
689"\xFB\xFA" => "\xEE\xDE",
690"\xFB\xD3" => "\xEE\xB7",
691"\xFA\x80" => "\xED\x63",
692"\xFB\xDA" => "\xEE\xBE",
693"\xFA\xC4" => "\xED\xA8",
694"\xFB\x50" => "\xED\xF1",
695"\xFB\xEA" => "\xEE\xCE",
696"\xFB\x78" => "\xEE\x5C",
697"\xFA\xE3" => "\xED\xC7",
698"\xFB\x9A" => "\xEE\x7D",
699"\xFB\xE6" => "\xEE\xCA",
700"\xFA\xA3" => "\xED\x87",
701"\xFB\x76" => "\xEE\x5A",
702"\xFB\xE7" => "\xEE\xCB",
703"\xFB\xF6" => "\xEE\xDA",
704"\xFA\xED" => "\xED\xD1",
705"\xFB\xF7" => "\xEE\xDB",
706"\xFA\x5F" => "\xED\x43",
707"\xFB\x9B" => "\xEE\x7E",
708"\xFB\xF9" => "\xEE\xDD",
709"\xFA\x8E" => "\xED\x71",
710"\xFC\x49" => "\xEE\xEA",
711"\xFA\xDA" => "\xED\xBE",
712"\xFB\x53" => "\xED\xF4",
713"\xFA\xC8" => "\xED\xAC",
714"\xFA\xBC" => "\xED\xA0",
715"\xFB\xB0" => "\xEE\x94",
716"\xFB\xE4" => "\xEE\xC8",
717"\xFA\x62" => "\xED\x46",
718"\xFA\x88" => "\xED\x6B",
719"\xFA\x7B" => "\xED\x5F",
720"\xFB\xDF" => "\xEE\xC3",
721"\xFA\xA9" => "\xED\x8D",
722"\xFA\x5C" => "\xED\x40",
723"\xFB\xA1" => "\xEE\x85",
724"\xFC\x43" => "\xEE\xE4",
725"\xFA\x6B" => "\xED\x4F",
726"\xFA\xAD" => "\xED\x91",
727"\xFA\x6C" => "\xED\x50",
728"\xFA\xC2" => "\xED\xA6",
729"\xFA\xEF" => "\xED\xD3",
730"\xFA\xA6" => "\xED\x8A",
731"\xFA\x68" => "\xED\x4C",
732"\xFA\x93" => "\xED\x76",
733"\xFB\x9C" => "\xEE\x80",
734"\xFA\x9D" => "\xED\x81",
735"\xFB\xEC" => "\xEE\xD0",
736"\xFB\x70" => "\xEE\x54",
737"\xFA\xAA" => "\xED\x8E",
738);
739
740sub _sjis2euc {
741	my($c1,$c2) = @_;
742
743	$c1 = ord($c1);
744	$c2 = ord($c2);
745	chr((($c1 - ($c1 < 160 ? 112 : 176)) << 1) - ($c2 < 159) + 128)
746	 . chr($c2 - (($c2 < 159) ? ($c2 > 127 ? 32 : 31) : 126) + 128);
747}
748
749sub sjis2euc {
750	my($string) = @_;
751	my ($j,$c,$c2,@c);
752	my $ctype = '1';	# 1:ASCII  K:���p�J�i  2:2�o�C�g����
753	my $result;
754
755	@c = split(//,$string);
756	for( $j = 0; $j <= $#c; $j++ ) {
757		$c = $c[$j];
758		if( $c =~ /[\x00-\x7f]/ ) {
759			$result .= $c;
760		} elsif( $c =~ /[\x81-\x9f\xe0-\xef]/ ) {
761			last if( ++$j > $#c ); $c2 = $c[$j];
762			if( $c2 =~ /[\x40-\xfc]/ ) {
763				$result .= _sjis2euc($c,$c2);
764			} else {
765				$result .= $c . $c2;
766			}
767		} elsif( $c ge "\xfa" ) {
768			last if( ++$j > $#c ); $c2 = $c[$j];
769			if( $extin{$c.$c2} ) {
770				$result .= _sjis2euc(split(//, $extin{$c.$c2}));
771			} else {
772				$result .= "\xa2\xa3";
773			}
774		} elsif( $c =~ /[\xa1-\xdf]/ ) {
775			$result .= "\x8e" . $c;
776		} else {
777			$result .= $c;
778		}
779	}
780	$result;
781}
782