1/*
2 * Copyright 2006, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan Aßmus <superstippi@gmx.de>
7 */
8
9//----------------------------------------------------------------------------
10// Anti-Grain Geometry - Version 2.2
11// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
12//
13// Permission to copy, use, modify, sell and distribute this software
14// is granted provided this copyright notice appears in all copies.
15// This software is provided "as is" without express or implied
16// warranty, and with no claim as to its suitability for any purpose.
17//
18//----------------------------------------------------------------------------
19// Contact: mcseem@antigrain.com
20//		  mcseemagg@yahoo.com
21//		  http://www.antigrain.com
22
23#include "PathTokenizer.h"
24
25#include <string.h>
26#include <stdlib.h>
27#include <stdio.h>
28
29
30namespace agg {
31namespace svg {
32
33// globals
34const char PathTokenizer::sCommands[]   = "+-MmZzLlHhVvCcSsQqTtAaFfPp";
35const char PathTokenizer::sNumeric[]	= ".Ee0123456789";
36const char PathTokenizer::sSeparators[] = " ,\t\n\r";
37
38// constructor
39PathTokenizer::PathTokenizer()
40	: fPath(0),
41	  fLastNumber(0.0),
42	  fLastCommand(0)
43{
44	init_char_mask(fCommandsMask,   sCommands);
45	init_char_mask(fNumericMask,	sNumeric);
46	init_char_mask(fSeparatorsMask, sSeparators);
47}
48
49// set_path_str
50void
51PathTokenizer::set_path_str(const char* str)
52{
53	fPath = str;
54	fLastCommand = 0;
55	fLastNumber = 0.0;
56}
57
58// next
59bool
60PathTokenizer::next()
61{
62	if(fPath == 0) return false;
63
64	// Skip all white spaces and other garbage
65	while (*fPath && !is_command(*fPath) && !isNumeric(*fPath))  {
66		if (!is_separator(*fPath)) {
67			char buf[100];
68			sprintf(buf, "PathTokenizer::next : Invalid Character %c", *fPath);
69			throw exception(buf);
70		}
71		fPath++;
72	}
73
74	if (*fPath == 0) return false;
75
76	if (is_command(*fPath)) {
77		// Check if the command is a numeric sign character
78		if(*fPath == '-' || *fPath == '+')
79		{
80			return parse_number();
81		}
82		fLastCommand = *fPath++;
83		while(*fPath && is_separator(*fPath)) fPath++;
84		if(*fPath == 0) return true;
85	}
86	return parse_number();
87}
88
89// next
90double
91PathTokenizer::next(char cmd)
92{
93	if (!next()) throw exception("parse_path: Unexpected end of path");
94	if (last_command() != cmd) {
95		char buf[100];
96		sprintf(buf, "parse_path: Command %c: bad or missing parameters", cmd);
97		throw exception(buf);
98	}
99	return last_number();
100}
101
102// init_char_mask
103void
104PathTokenizer::init_char_mask(char* mask, const char* char_set)
105{
106	memset(mask, 0, 256/8);
107	while (*char_set) {
108		unsigned c = unsigned(*char_set++) & 0xFF;
109		mask[c >> 3] |= 1 << (c & 7);
110	}
111}
112
113// contains
114inline bool
115PathTokenizer::contains(const char* mask, unsigned c) const
116{
117	return (mask[(c >> 3) & (256 / 8 - 1)] & (1 << (c & 7))) != 0;
118}
119
120// is_command
121inline bool
122PathTokenizer::is_command(unsigned c) const
123{
124	return contains(fCommandsMask, c);
125}
126
127// isNumeric
128inline bool
129PathTokenizer::isNumeric(unsigned c) const
130{
131	return contains(fNumericMask, c);
132}
133
134// is_separator
135inline bool
136PathTokenizer::is_separator(unsigned c) const
137{
138	return contains(fSeparatorsMask, c);
139}
140
141// parse_number
142bool
143PathTokenizer::parse_number()
144{
145	char* end;
146	fLastNumber = strtod(fPath, &end);
147	fPath = end;
148	return true;
149}
150
151
152} //namespace svg
153} //namespace agg
154
155
156
157
158