gloox  1.0.9
util.cpp
1 /*
2  Copyright (c) 2006-2013 by Jakob Schroeter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 #include "util.h"
14 #include "gloox.h"
15 
16 #include <cstdio>
17 
18 namespace gloox
19 {
20 
21  namespace util
22  {
23 
24  int internalLog2( unsigned int n )
25  {
26  int pos = 0;
27  if ( n >= 1<<16 ) { n >>= 16; pos += 16; }
28  if ( n >= 1<< 8 ) { n >>= 8; pos += 8; }
29  if ( n >= 1<< 4 ) { n >>= 4; pos += 4; }
30  if ( n >= 1<< 2 ) { n >>= 2; pos += 2; }
31  if ( n >= 1<< 1 ) { pos += 1; }
32  return ( (n == 0) ? (-1) : pos );
33  }
34 
35  unsigned _lookup( const std::string& str, const char* values[], unsigned size, int def )
36  {
37  unsigned i = 0;
38  for( ; i < size && str != values[i]; ++i )
39  ;
40  return ( i == size && def >= 0 ) ? (unsigned)def : i;
41  }
42 
43  const std::string _lookup( unsigned code, const char* values[], unsigned size, const std::string& def )
44  {
45  return code < size ? std::string( values[code] ) : def;
46  }
47 
48  unsigned _lookup2( const std::string& str, const char* values[],
49  unsigned size, int def )
50  {
51  return 1 << _lookup( str, values, size, def <= 0 ? def : (int)internalLog2( def ) );
52  }
53 
54  const std::string _lookup2( unsigned code, const char* values[], unsigned size, const std::string& def )
55  {
56  const unsigned i = (unsigned)internalLog2( code );
57  return i < size ? std::string( values[i] ) : def;
58  }
59 
60  std::string hex( const std::string& input )
61  {
62  const char* H = input.c_str();
63  char* buf = new char[input.length() * 2 + 1];
64  for( unsigned int i = 0; i < input.length(); ++i )
65  sprintf( buf + i * 2, "%02x", (unsigned char)( H[i] ) );
66  return std::string( buf, 40 );
67  }
68 
69  static const char escape_chars[] = { '&', '<', '>', '\'', '"' };
70 
71  static const std::string escape_seqs[] = { "amp;", "lt;", "gt;", "apos;", "quot;" };
72 
73  static const std::string escape_seqs_full[] = { "&amp;", "&lt;", "&gt;", "&apos;", "&quot;" };
74 
75  static const unsigned escape_size = 5;
76 
77  const std::string escape( std::string what )
78  {
79  for( size_t val, i = 0; i < what.length(); ++i )
80  {
81  for( val = 0; val < escape_size; ++val )
82  {
83  if( what[i] == escape_chars[val] )
84  {
85  what[i] = '&';
86  what.insert( i+1, escape_seqs[val] );
87  i += escape_seqs[val].length();
88  break;
89  }
90  }
91  }
92  return what;
93  }
94 
95  void appendEscaped( std::string& target, const std::string& data )
96  {
97  size_t rangeStart = 0, rangeCount = 0;
98  size_t length = data.length();
99  const char* dataPtr = data.data();
100  for( size_t val, i = 0; i < length; ++i )
101  {
102  const char current = dataPtr[i];
103  for( val = 0; val < escape_size; ++val )
104  {
105  if( current == escape_chars[val] )
106  {
107  // We have a character that needs to be escaped.
108  if( rangeCount > 0 )
109  {
110  // We have a range of the data that needs to be appended
111  // before we escape the current character.
112  // NOTE: Use "data" (std::string) here not dataPtr (const char*).
113  // Both have the same content, but there isn't
114  // an append override that takes const char*, pos, n
115  // (so a temporary std::string would be created)
116  target.append( data, rangeStart, rangeCount );
117  }
118  target.append( escape_seqs_full[val] );
119  rangeStart = i + 1;
120  rangeCount = 0;
121  break;
122  }
123  }
124 
125  if( rangeStart <= i )
126  {
127  // current did not need to be escaped
128  ++rangeCount;
129  }
130  }
131 
132  if( rangeCount > 0 )
133  {
134  // Append the remaining pending range of data that does
135  // not need to be escaped.
136  // NOTE: See previous comment on using data not dataPtr for append.
137  target.append( data, rangeStart, rangeCount );
138  }
139  }
140 
141  bool checkValidXMLChars( const std::string& data )
142  {
143  if( data.empty() )
144  return true;
145 
146  const char* dataPtr = data.data();
147  const char* end = dataPtr + data.length();
148  for( ; dataPtr != end; ++dataPtr )
149  {
150  unsigned char current = (unsigned char) *dataPtr;
151  if( current < 0x20 )
152  {
153  if( current == 0x09
154  || current == 0x0a
155  || current == 0x0d )
156  // Valid character
157  continue;
158  else
159  // Invalid character
160  break;
161  }
162  else if( current >= 0xf5 )
163  // Invalid character
164  break;
165  else if( current == 0xc0
166  || current == 0xc1 )
167  // Invalid character
168  break;
169  else
170  // Valid character
171  continue;
172  }
173 
174  return ( dataPtr == end );
175  }
176 
177  void replaceAll( std::string& target, const std::string& find, const std::string& replace )
178  {
179  std::string::size_type findSize = find.size();
180  std::string::size_type replaceSize = replace.size();
181 
182  if( findSize == 0 )
183  return;
184 
185  std::string::size_type index = target.find( find, 0 );
186 
187  while( index != std::string::npos )
188  {
189  target.replace( index, findSize, replace );
190  index = target.find( find, index+replaceSize );
191  }
192  }
193 
194  }
195 
196 }
197