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