Claw  1.7.3
xbm_reader.cpp
Go to the documentation of this file.
1 /*
2  CLAW - a C++ Library Absolutely Wonderful
3 
4  CLAW is a free library without any particular aim but being useful to
5  anyone.
6 
7  Copyright (C) 2005-2011 Julien Jorge
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 
23  contact: julien.jorge@gamned.org
24 */
30 #include <claw/xbm.hpp>
31 
32 #include <claw/exception.hpp>
33 #include <claw/assert.hpp>
35 
36 /*----------------------------------------------------------------------------*/
42  : m_image( img ), m_hot(NULL)
43 {
44 
45 } // xbm::reader::reader()
46 
47 /*----------------------------------------------------------------------------*/
54 claw::graphic::xbm::reader::reader( image& img, std::istream& f )
55  : m_image( img ), m_hot(NULL)
56 {
57  load(f);
58 } // xbm::reader::reader()
59 
60 /*----------------------------------------------------------------------------*/
67 claw::graphic::xbm::reader::reader( xbm& img, std::istream& f )
68  : m_image( img ), m_hot(NULL)
69 {
70  load(f);
71  img.set_name( m_name );
72 
73  if (m_hot != NULL)
74  img.set_hot( *m_hot );
75 } // xbm::reader::reader()
76 
77 /*----------------------------------------------------------------------------*/
82 {
83  if (m_hot != NULL)
84  {
85  delete m_hot;
86  m_hot = NULL;
87  }
88 } // xbm::reader::~reader()
89 
90 /*----------------------------------------------------------------------------*/
95 void claw::graphic::xbm::reader::load( std::istream& f )
96 {
97  CLAW_PRECOND( !!f );
98 
99  std::istream::pos_type init_pos = f.tellg();
100 
101  if (m_hot != NULL)
102  {
103  delete m_hot;
104  m_hot = NULL;
105  }
106 
107  try
108  {
109  read_from_file(f);
110  }
111  catch(...)
112  {
113  if (m_hot != NULL)
114  delete m_hot;
115 
116  f.clear();
117  f.seekg( init_pos, std::ios_base::beg );
118  throw;
119  }
120 } // xbm::reader::load()
121 
122 /*----------------------------------------------------------------------------*/
127 void claw::graphic::xbm::reader::read_from_file( std::istream& f )
128 {
129  std::string line;
130  bool valid_format = false;
131  unsigned int bpe;
132 
133  read_size(f);
134  bpe = read_bits_per_entry(f);
135  read_name(f);
136  read_line( f, line, '{' );
137 
138  if ( !line.empty() )
139  {
140  read_pixels(f, bpe);
141  read_line(f, line, ';');
142 
143  valid_format = true;
144  }
145 
146  if ( !valid_format )
147  throw claw::exception( "Not an XBM file." );
148 } // xbm::reader::read_from_file()
149 
150 /*----------------------------------------------------------------------------*/
155 void claw::graphic::xbm::reader::read_size( std::istream& f )
156 {
157  unsigned int w(0), h(0);
158  bool valid = true;
159  bool stop = false;
160  std::string line;
161 
162  while ( valid && !stop )
163  {
164  std::ios::pos_type pos = f.tellg();
165 
166  read_line( f, line, '\n' );
167 
168  if ( !line.empty() )
169  {
170  if ( line.find("width") != std::string::npos )
171  w = read_dim(line);
172  else if ( line.find("height") != std::string::npos )
173  h = read_dim(line);
174  else if ( line.find("x_hot") != std::string::npos )
175  {
176  if ( m_hot == NULL )
177  m_hot = new claw::math::coordinate_2d<int>;
178 
179  m_hot->x = read_dim(line);
180  }
181  else if ( line.find("y_hot") != std::string::npos )
182  {
183  if ( m_hot == NULL )
184  m_hot = new claw::math::coordinate_2d<int>;
185 
186  m_hot->y = read_dim(line);
187  }
188  else if ( line.find("static") != std::string::npos )
189  {
190  stop = true;
191  f.seekg( pos );
192  }
193  }
194  else
195  valid = false;
196  }
197 
198  if ( valid )
199  m_image.set_size(w, h);
200  else
201  throw claw::exception( "Not an XBM file." );
202 } // xbm::reader::read_size()
203 
204 /*----------------------------------------------------------------------------*/
209 unsigned int
210 claw::graphic::xbm::reader::read_dim( const std::string& line ) const
211 {
212  unsigned int result;
213  std::istringstream iss(line);
214  std::string token;
215  bool valid = false;
216 
217  if (iss >> token)
218  if ( token == "#define" )
219  if ( iss >> token )
220  if ( iss >> result )
221  valid = true;
222 
223  if ( !valid )
224  throw claw::exception( "Not an XBM file." );
225 
226  return result;
227 } // xbm::reader::read_dim()
228 
229 /*----------------------------------------------------------------------------*/
234 unsigned int
235 claw::graphic::xbm::reader::read_bits_per_entry( std::istream& f ) const
236 {
237  std::string line;
238  unsigned int result(0);
239 
240  std::string token;
241 
242  if ( f >> token )
243  if ( token == "static" )
244  if ( f >> token )
245  {
246  if ( token == "unsigned" )
247  f >> token;
248  else if ( token == "signed" )
249  f >> token;
250 
251  if ( token == "char" )
252  result = sizeof(char) * 8;
253  else if ( token == "short" )
254  result = sizeof(short) * 8;
255  else if ( token == "int" )
256  result = sizeof(int) * 8;
257  else if ( token == "long" )
258  result = sizeof(long) * 8;
259  }
260 
261  if ( result == 0 )
262  throw claw::exception( "Not an XBM file." );
263 
264  return result;
265 } // xbm::reader::read_bits_per_entry()
266 
267 /*----------------------------------------------------------------------------*/
272 void claw::graphic::xbm::reader::read_name( std::istream& f )
273 {
274  bool valid = false;
275  std::string line;
276 
277  read_line(f, line, '[');
278 
279  if ( !line.empty() )
280  {
281  std::string::size_type end = line.find_last_of('_');
282 
283  if ( end != std::string::npos )
284  {
285  std::string::size_type begin = line.find_last_of(" \t", end);
286 
287  if ( begin == std::string::npos )
288  begin = 0;
289 
290  m_name = line.substr(begin, end - begin);
291  valid = true;
292  }
293  }
294 
295  if ( !valid )
296  throw claw::exception( "Not an XBM file." );
297 } // xbm::reader::read_name()
298 
299 /*----------------------------------------------------------------------------*/
305 void claw::graphic::xbm::reader::read_pixels
306 ( std::istream& f, unsigned int bpe ) const
307 {
308  image::iterator first = m_image.begin();
309  const image::iterator last = m_image.end();
310 
311  bool valid = true;
312 
313  unsigned int x = 0;
314 
315  while ( (first!=last) && valid )
316  {
317  std::string s_val;
318  read_line( f, s_val, ',' );
319 
320  std::istringstream iss(s_val);
321  long int val;
322 
323  if ( iss >> std::hex >> val )
324  {
325  for( unsigned int i=0;
326  (i!=bpe) && (first!=last) && (x!=m_image.width());
327  ++i, ++first, ++x, val >>= 1 )
328  if ( val & 1 )
329  *first = black_pixel;
330  else
331  *first = white_pixel;
332 
333  if ( x==m_image.width() )
334  x = 0;
335  }
336  else
337  valid = false;
338  }
339 
340  if ( !valid )
341  throw claw::exception( "Not an XBM file." );
342 } // xbm::reader::read_pixels()
343 
344 /*----------------------------------------------------------------------------*/
351 void claw::graphic::xbm::reader::read_line
352 ( std::istream& f, std::string& line, char endchar ) const
353 {
354  bool stop = false;
355 
356  line.clear();
357 
358  while ( !stop )
359  if ( std::getline( f, line, endchar ) )
360  {
361  text::trim(line);
362 
363 
364  remove_comments(f, line, endchar);
365  stop = !line.empty();
366  }
367  else
368  stop = true;
369 } // xbm::reader::read_line()
370 
371 /*----------------------------------------------------------------------------*/
379 void claw::graphic::xbm::reader::remove_comments
380 ( std::istream& f, std::string& line, char endchar ) const
381 {
382  std::string working(line);
383  std::string::size_type beg = working.find( "/*" );
384 
385  if ( beg != std::string::npos )
386  {
387  line = working.substr(0, beg);
388 
389  std::string::size_type end = working.rfind( "*/" );
390  bool stop = false;
391 
392  while ( (end == std::string::npos) && !stop )
393  if ( std::getline(f, working, endchar) )
394  end = working.find( "*/" );
395  else
396  stop = true;
397 
398  if ( !stop )
399  {
400  line += working.substr(end+2, line.length() - end - 2);
401  text::trim(line);
402  }
403 
404  if ( !line.empty() )
405  remove_comments(f, line, endchar);
406  }
407 } // xbm::reader::remove_comments()