File Coverage

blib/lib/IP/Location.pm
Criterion Covered Total %
statement 18 132 13.6
branch 0 30 0.0
condition 0 6 0.0
subroutine 6 13 46.1
pod 6 7 85.7
total 30 188 15.9


line stmt bran cond sub pod time code
1             package IP::Location;
2              
3 1     1   5684 use 5.006000;
  1         3  
  1         39  
4 1     1   5 use strict;
  1         2  
  1         33  
5 1     1   6 use warnings;
  1         13  
  1         36  
6 1     1   906 use FileHandle;
  1         11789  
  1         6  
7 1     1   1235 use Encode;
  1         11245  
  1         94  
8 1     1   614 use Encode::CNMap;
  1         2623  
  1         1501  
9             require Exporter;
10              
11             our @ISA = qw(Exporter);
12              
13             # Items to export into callers namespace by default. Note: do not export
14             # names by default without a very good reason. Use EXPORT_OK instead.
15             # Do not simply export all your public functions/methods/constants.
16              
17             # This allows declaration use IP::Location ':all';
18             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
19             # will save memory.
20             our %EXPORT_TAGS = ( 'all' => [ qw(
21            
22             ) ] );
23              
24             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
25              
26             our @EXPORT = qw(
27            
28             );
29              
30             our $VERSION = '0.01';
31              
32             sub new {
33 0     0 1   my ($class, @args) = @_;
34 0           my $self = {
35             'CHAR_SET' => 'GBK',
36             'IP_ENTRY_NUM' => undef,
37             'VERSION' => undef,
38             'QQWRY' => undef,
39             'FIRST_INDEX_OFFSET' => undef,
40             'LAST_INDEX_OFFSET' => undef,
41             };
42              
43 0           bless($self, $class);
44              
45 0 0         $self->init(@args) if @args;
46            
47 0           return $self;
48             }
49              
50             sub init {
51 0     0 1   my ($self, $datafile, $char_set) = @_;
52 0           my ($First_Index_Offset, $Last_Index_Offset);
53 0           $self->{'QQWRY'} = FileHandle->new("< $datafile");
54 0           binmode($self->{'QQWRY'});
55 0           sysread($self->{'QQWRY'}, $First_Index_Offset, 4);
56 0           sysread($self->{'QQWRY'}, $Last_Index_Offset, 4);
57              
58 0           $First_Index_Offset = unpack("L", $First_Index_Offset);
59 0           $Last_Index_Offset = unpack("L", $Last_Index_Offset);
60              
61 0           $self->{FIRST_INDEX_OFFSET} = $First_Index_Offset;
62 0           $self->{LAST_INDEX_OFFSET} = $Last_Index_Offset;
63 0           $self->{IP_ENTRY_NUM} = ($Last_Index_Offset - $First_Index_Offset) / 7 + 1;
64              
65 0 0         $self->char_set($char_set) if $char_set;
66             }
67              
68             sub locate {
69 0     0 1   my ($self, $IP_Target) = @_;
70 0           my ($IP_Entry_Cursor1, $IP_Entry_Cursor2, $IP_Entry_Cursor3);
71 0           my $IP_Entry_Data;
72 0           my $IP_Seek_Cursor;
73 0           my $QQWRY = $self->{'QQWRY'};
74 0           my $IP_Seek_Cursor_Tmp;
75             my $Redirct_Flags;
76 0           my ($IP_Target_Country, $IP_Target_Area, $IP_Target_Location);
77 0           my @IP_Target = split(/\./, $IP_Target);
78            
79 0           $IP_Target = $IP_Target[0] * 16777216 + $IP_Target[1] * 65536 + $IP_Target[2] * 256 + $IP_Target[3];
80              
81 0           $IP_Entry_Cursor1 = 0;
82 0           $IP_Entry_Cursor3 = $self->{IP_ENTRY_NUM};
83            
84 0           WHILE:
85             $IP_Entry_Cursor2 = int(($IP_Entry_Cursor1 + $IP_Entry_Cursor3)/2);
86            
87 0           seek($self->{'QQWRY'}, $self->{FIRST_INDEX_OFFSET} + $IP_Entry_Cursor2 * 7, 0);
88 0           read($self->{'QQWRY'}, $IP_Entry_Data, 4);
89            
90 0           $IP_Entry_Data = unpack("L", $IP_Entry_Data);
91 0 0         if ($IP_Target < $IP_Entry_Data) {
92 0           $IP_Entry_Cursor3 = $IP_Entry_Cursor2;
93 0           goto WHILE;
94             }
95              
96 0           read($self->{'QQWRY'}, $IP_Seek_Cursor, 3);
97 0           $IP_Seek_Cursor = unpack("L", $IP_Seek_Cursor."\0");
98 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor, 0);
99 0           read($self->{'QQWRY'}, $IP_Entry_Data, 4);
100 0           $IP_Entry_Data = unpack("L", $IP_Entry_Data);
101              
102 0 0         if ($IP_Entry_Data < $IP_Target) {
103 0 0         if ($IP_Entry_Cursor1 == $IP_Entry_Cursor2) {
104 0           goto LAST;}
105 0           $IP_Entry_Cursor1 = $IP_Entry_Cursor2;
106 0           goto WHILE;
107             }
108            
109 0           $/ = "\0";
110              
111 0           read($self->{'QQWRY'}, $Redirct_Flags, 1);
112              
113 0 0         if ($Redirct_Flags eq "\1") {
    0          
114 0           read($self->{'QQWRY'}, $IP_Seek_Cursor, 3);
115 0           $IP_Seek_Cursor = unpack("L", $IP_Seek_Cursor."\0");
116            
117 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor, 0);
118 0           read($self->{'QQWRY'}, $Redirct_Flags, 1);
119 0 0         if ($Redirct_Flags eq "\2") {
120 0           $IP_Seek_Cursor_Tmp = $IP_Seek_Cursor;
121 0           read($self->{'QQWRY'}, $IP_Seek_Cursor, 3);
122 0           $IP_Seek_Cursor = unpack("L", $IP_Seek_Cursor."\0");
123 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor, 0);
124 0           $IP_Target_Country=<$QQWRY>;
125 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor_Tmp + 4, 0);
126 0           read($self->{'QQWRY'}, $Redirct_Flags, 1);
127            
128 0 0         if ($Redirct_Flags eq "\2") {
129 0           read($self->{'QQWRY'}, $IP_Seek_Cursor, 3);
130 0           $IP_Seek_Cursor = unpack("L", $IP_Seek_Cursor."\0");
131 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor, 0);
132 0           $IP_Target_Area=<$QQWRY>;
133             }
134             else {
135              
136 0           $IP_Target_Area=<$QQWRY>;
137             }
138             }
139             else {
140 0           seek($self->{'QQWRY'}, -1, 1);
141 0           $IP_Target_Country=<$QQWRY>;
142 0           read($self->{'QQWRY'}, $Redirct_Flags, 1);
143 0 0         if ($Redirct_Flags eq "\2") {
144 0           read($self->{'QQWRY'}, $IP_Seek_Cursor, 3);
145 0           $IP_Seek_Cursor = unpack("L", $IP_Seek_Cursor."\0");
146 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor, 0);
147             }
148 0           $IP_Target_Area=<$QQWRY>;
149             }
150             }
151             elsif ($Redirct_Flags eq "\2") {
152 0           $IP_Seek_Cursor_Tmp = ($IP_Seek_Cursor + 8);
153 0           read($self->{'QQWRY'}, $IP_Seek_Cursor, 3);
154 0           $IP_Seek_Cursor = unpack("L", $IP_Seek_Cursor."\0");
155 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor, 0);
156 0           $IP_Target_Country=<$QQWRY>;
157 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor_Tmp, 0);
158 0           $IP_Target_Area=<$QQWRY>;
159             }
160             else {
161 0           seek($self->{'QQWRY'}, -1, 1);
162 0           $IP_Target_Country=<$QQWRY>;
163              
164 0           read($self->{'QQWRY'}, $Redirct_Flags, 1);
165 0 0         if ($Redirct_Flags eq "\2") {
166 0           read($self->{'QQWRY'}, $IP_Seek_Cursor, 3);
167 0           $IP_Seek_Cursor = unpack("L", $IP_Seek_Cursor."\0");
168 0           seek($self->{'QQWRY'}, $IP_Seek_Cursor, 0);
169             }
170             else {
171 0           seek($self->{'QQWRY'}, -1, 1);
172             }
173 0           $IP_Target_Area = <$QQWRY>;
174             }
175            
176 0           LAST:
177              
178             chomp($IP_Target_Country, $IP_Target_Area);
179 0           $/ = "\n";
180              
181 0           $IP_Target_Area =~ s/CZ88\.NET//gi;
182 0           $IP_Target_Location = "$IP_Target_Country $IP_Target_Area";
183 0           $IP_Target_Location =~ s/^\s*(.*)\s*$/$1/g;
184 0 0 0       $IP_Target_Location = "未知区域" if ($IP_Target_Location =~ m/未知|http/i || $IP_Target_Location eq "");
185              
186 0           return $self->conv($IP_Target_Location);
187             }
188              
189             sub conv {
190 0     0 0   my ($self, $string) = @_;
191              
192 0 0         return simp_to_utf8($string) if $self->{'CHAR_SET'} eq 'UTF-8';
193 0           return $string;
194             }
195              
196             sub char_set {
197 0     0 1   my ($self, $Char_Set) = @_;
198              
199 0 0         if ($Char_Set) {
200 0 0 0       if ($Char_Set ne 'GBK' && $Char_Set ne 'UTF-8') {
201 0           print "Error : CHAR_SET should be either \'GBK\' or \'UTF-8\'!";
202 0           return;
203             }
204            
205 0           $self->{CHAR_SET} = $Char_Set;
206 0           return $self->conv($self->{CHAR_SET});
207             }
208             else {
209 0           return $self->conv($self->{CHAR_SET});
210             }
211             }
212              
213             sub version {
214 0     0 1   my $self = shift;
215              
216 0           return $self->locate("255.255.255.0");
217             }
218              
219             sub info {
220 0     0 1   my $self = shift;
221              
222 0           my $info1 = "QQWRY version : ";
223 0           my $info2 = "\n"
224             . "Total Entries : "
225             . $self->{'IP_ENTRY_NUM'}
226             . "\n"
227             . "IP::Location version : $VERSION\n";
228              
229 0           return $self->conv($info1)
230             . $self->locate("255.255.255.0")
231             . $self->conv($info2);
232             }
233             # Preloaded methods go here.
234              
235             1;
236             __END__