1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
37
  
38
  
39
  
40
  
41
  
42
  
43
  
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
#pike __REAL_VERSION__ 
 
constant contenttypes = ({}); 
 
string low_decode_charset( string data, string charset ) 
{ 
  switch( replace(lower_case( charset ),"-","_")-"_" ) 
  { 
    case "iso88591": 
      return data; 
    case "ucs2": 
    case "unicode": 
      return unicode_to_string( data ); 
      break; 
    case "utf8": 
      return utf8_to_string( data ); 
 
    case "euc": 
    case "xeuc": 
      /* should default depending on domain */ 
    case "eucjp": 
    case "eucjapan": 
    case "japanese": 
      return Charset.decoder( "euc-jp" )->feed( data )->drain(); 
 
    case "xsjis": 
    case "shiftjis": 
    case "jis": 
      return Charset.decoder("Shift_JIS")->feed(data)->drain(); 
       
    default: 
      catch { 
        return Charset.decoder( charset )->feed( data )->drain(); 
      }; 
      werror("\n****** Warning: Unknown charset: '"+charset+"'\n"); 
      return data; 
  } 
} 
 
string decode_charset( string data, string charset ) 
{ 
  mixed err = catch { 
    return low_decode_charset(data, charset); 
  }; 
  werror("\n****** Warning: Invalid character encoding: %s", 
         describe_error(err)); 
  return data; 
} 
 
string decode_http( string data, mapping headers, 
                    string default_charset ) 
{ 
  // 1: Is there a Content-type location with a charset specifier? 
  string ct; 
  if( (ct = headers["content-type"]) 
      && sscanf( ct, "%*scharset=%[^;]", ct ) == 2 ) 
      return decode_charset( data,  String.trim_all_whites( ct ) ); 
 
  // 2: Find <meta> header in the first Kb of data. 
  int done; 
  array do_meta(Parser.HTML p, mapping m) 
  { 
    if( done ) return ({}); 
    if( (lower_case(m->name||"")=="content-type")         || 
        (lower_case(m["http-equiv"]||"")=="content-type") || 
        (lower_case(m["httpequiv"]||"")=="content-type")  || 
        (lower_case(m["http-equiv"]||"")=="contenttype")  || 
        (lower_case(m["httpequiv"]||"")=="contenttype") ) 
    { 
      if( (ct = m->content||m->data)  
          && sscanf( ct, "%*scharset=%[^;]", ct ) == 2 ) 
      { 
        data=decode_charset( data, String.trim_all_whites( ct )); 
        done=1; 
      } 
    } 
    return ({}); 
  }; 
 
  Parser.HTML p = Parser.HTML()->add_tag( "meta", do_meta ); 
  p->ignore_unknown(1); 
  p->match_tag(0); 
  p->case_insensitive_tag(1); 
  p->feed( data[..1024] ); 
  p->finish(); 
 
  if( done ) 
    return data; 
 
  // 3: DWIM. 
 
  // 3.1: \0 here and there -> ucs2.. 
  if( sizeof(data[..40]/"\0") > 5 ) 
    return unicode_to_string( data ); 
 
  // 3.2: iso-2022, probably 
  if( sizeof(data[..100]/"\33$") > 1 ) 
    return Charset.decoder( "iso-2022-jp")->feed( data )->drain(); 
 
  return default_charset ? decode_charset( data, default_charset ) : data; 
}