| 1 | cycrow | 1 | #include "bod_cut_parser.h"
 | 
        
           |  |  | 2 | #include "../common/strutils.h"
 | 
        
           |  |  | 3 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 4 | bool bod_cut_parser::compile(token_stream& is, obinaryfilestream& os)
 | 
        
           | 1 | cycrow | 5 | {
 | 
        
           | 114 | cycrow | 6 | 	os << bob_dom_cut::HDR_BEGIN;
 | 
        
           |  |  | 7 |   | 
        
           | 1 | cycrow | 8 | 	bob_dom_cut *cut=loadCUT(is, &os, true);
 | 
        
           | 114 | cycrow | 9 |   | 
        
           | 1 | cycrow | 10 | 	//if(cut)
 | 
        
           |  |  | 11 | 		//cut->toFile(os);
 | 
        
           | 114 | cycrow | 12 |   | 
        
           | 1 | cycrow | 13 | 	delete cut;
 | 
        
           | 114 | cycrow | 14 |   | 
        
           |  |  | 15 | 	os << bob_dom_cut::HDR_END;
 | 
        
           |  |  | 16 |   | 
        
           | 1 | cycrow | 17 | 	return cut!=NULL;
 | 
        
           |  |  | 18 | }
 | 
        
           |  |  | 19 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 20 | bob_dom_cut * bod_cut_parser::loadCUT(token_stream& is)
 | 
        
           |  |  | 21 | {
 | 
        
           | 114 | cycrow | 22 | 	obinaryfilestream *dummy=0;
 | 
        
           |  |  | 23 |   | 
        
           | 1 | cycrow | 24 | 	return loadCUT(is, dummy, false);
 | 
        
           |  |  | 25 | }
 | 
        
           |  |  | 26 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 27 | // this is bit weird function as it serves for 2 purposes: it can return loaded cut object
 | 
        
           |  |  | 28 | // or it can directly output parts of cut as it's being loaded
 | 
        
           | 114 | cycrow | 29 | bob_dom_cut * bod_cut_parser::loadCUT(token_stream& is, obinaryfilestream *os, bool bDirectOutput)
 | 
        
           | 1 | cycrow | 30 | {
 | 
        
           |  |  | 31 | 	bod_text_parser::token *t;
 | 
        
           | 114 | cycrow | 32 | 	bob_path *actPath=0;
 | 
        
           |  |  | 33 | 	bob_stat *actStat=0;
 | 
        
           | 1 | cycrow | 34 | 	bob_dom_cut *cut=new bob_dom_cut(m_settings);
 | 
        
           | 114 | cycrow | 35 |   | 
        
           | 1 | cycrow | 36 | 	// used for direct output
 | 
        
           |  |  | 37 | 	int pathCountOffset;
 | 
        
           |  |  | 38 | 	int pathCount=0;
 | 
        
           | 114 | cycrow | 39 |   | 
        
           | 1 | cycrow | 40 | 	bool bErrors=false;
 | 
        
           |  |  | 41 | 	bool bRes=false;
 | 
        
           | 114 | cycrow | 42 |   | 
        
           | 1 | cycrow | 43 | 	while(is.good() && is.tok()->type==token::t_hdrinfo){
 | 
        
           |  |  | 44 | 		if(cut->info.text()!=0)
 | 
        
           |  |  | 45 | 			error(is.tok(), S_Warning, "Header info already defined, last value will be used");
 | 
        
           |  |  | 46 | 		cut->info.text(is.tok()->text);
 | 
        
           |  |  | 47 | 		++is;
 | 
        
           |  |  | 48 | 	}
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 | 	do{
 | 
        
           |  |  | 51 | 		// VERSION
 | 
        
           |  |  | 52 | 		t=is.tok();
 | 
        
           |  |  | 53 | 		if(t==NULL || t->type!=token::t_text || strcmp(t->text, "VER")!=0)
 | 
        
           |  |  | 54 | 			{ error(t ? t : is.previous(), S_Error, "Expected version specification"); break; }
 | 
        
           | 114 | cycrow | 55 |   | 
        
           | 1 | cycrow | 56 | 		t=(++is).tok();
 | 
        
           |  |  | 57 | 		if(t==NULL || t->type!=token::t_colon)
 | 
        
           |  |  | 58 | 			{ error(t ? t : is.previous(), S_Error, "Expected ':' after '%s'", is.previous()->text); break; }
 | 
        
           | 114 | cycrow | 59 |   | 
        
           |  |  | 60 | 		if(!checkImmediatePlacement(is.previous(), is.tok()))
 | 
        
           | 1 | cycrow | 61 | 			break;
 | 
        
           | 114 | cycrow | 62 |   | 
        
           | 1 | cycrow | 63 | 		if((t=loadValue(++is))==NULL)
 | 
        
           |  |  | 64 | 			break;
 | 
        
           |  |  | 65 | 		if(!isinteger(t->text))
 | 
        
           |  |  | 66 | 			{ error(t ? t : is.previous(), S_Error, "Expected version number after ':'"); break; }
 | 
        
           | 114 | cycrow | 67 |   | 
        
           | 1 | cycrow | 68 | 		cut->version=atoi(t->text);
 | 
        
           | 114 | cycrow | 69 |   | 
        
           | 1 | cycrow | 70 | 		if(cut->version > bob_dom_cut::supported_version)
 | 
        
           |  |  | 71 | 			error(is.tok(), S_Warning, "File version is %d, supported version is %d", cut->version, bob_dom_cut::supported_version);
 | 
        
           | 114 | cycrow | 72 |   | 
        
           | 1 | cycrow | 73 | 		if(bDirectOutput){
 | 
        
           |  |  | 74 | 			cut->info.toFile(*os);
 | 
        
           | 114 | cycrow | 75 | 			*os << cut->version;
 | 
        
           |  |  | 76 | 			/*
 | 
        
           |  |  | 77 | 				we must output the path count right now,
 | 
        
           | 1 | cycrow | 78 | 				but we will rewrite it once we finish
 | 
        
           |  |  | 79 | 			*/
 | 
        
           |  |  | 80 | 			pathCountOffset=(int)os->tell();
 | 
        
           | 114 | cycrow | 81 | 			*os << pathCount;
 | 
        
           | 1 | cycrow | 82 | 		}
 | 
        
           | 114 | cycrow | 83 |   | 
        
           | 1 | cycrow | 84 | 		while(is.good()){
 | 
        
           |  |  | 85 | 			t=is.tok();
 | 
        
           | 114 | cycrow | 86 |   | 
        
           |  |  | 87 | 			if(t->type==token::t_openCrBracket){
 | 
        
           | 1 | cycrow | 88 | 				if(actPath==NULL){
 | 
        
           |  |  | 89 | 					error(t, S_Error, "Block unexpected here.");
 | 
        
           |  |  | 90 | 					break;
 | 
        
           |  |  | 91 | 				}
 | 
        
           |  |  | 92 | 				else{
 | 
        
           | 114 | cycrow | 93 | 					bErrors|=!loadFrame(actPath, ++is);
 | 
        
           | 1 | cycrow | 94 | 				}
 | 
        
           |  |  | 95 | 			}
 | 
        
           | 114 | cycrow | 96 |   | 
        
           | 1 | cycrow | 97 | 			else{
 | 
        
           |  |  | 98 | 				if(actPath && bDirectOutput){
 | 
        
           |  |  | 99 | 					pathCount++;
 | 
        
           |  |  | 100 | 					actPath->toFile(*os, cut->version);
 | 
        
           |  |  | 101 | 					cut->removeChild(--cut->end());
 | 
        
           |  |  | 102 | 				}
 | 
        
           |  |  | 103 | 				if((actPath=loadPath(cut, is))==NULL)
 | 
        
           |  |  | 104 | 					break;
 | 
        
           | 114 | cycrow | 105 |   | 
        
           | 1 | cycrow | 106 | 				if(!is.good()){
 | 
        
           |  |  | 107 | 					error(is.previous(), S_Error, "Missing Frame declaration after Body declaration");
 | 
        
           |  |  | 108 | 					break;
 | 
        
           |  |  | 109 | 				}
 | 
        
           |  |  | 110 | 			}
 | 
        
           |  |  | 111 | 			bRes=!bErrors;
 | 
        
           |  |  | 112 | 		}
 | 
        
           |  |  | 113 | 	}
 | 
        
           |  |  | 114 | 	while(false);
 | 
        
           | 114 | cycrow | 115 |   | 
        
           | 1 | cycrow | 116 | 	if(actPath && bDirectOutput){
 | 
        
           |  |  | 117 | 		pathCount++;
 | 
        
           |  |  | 118 | 		actPath->toFile(*os, cut->version);
 | 
        
           |  |  | 119 | 		cut->removeChild(--cut->end());
 | 
        
           |  |  | 120 | 	}
 | 
        
           | 114 | cycrow | 121 |   | 
        
           | 1 | cycrow | 122 | 	if(bRes==false){
 | 
        
           |  |  | 123 | 		delete cut;
 | 
        
           |  |  | 124 | 		return NULL;
 | 
        
           |  |  | 125 | 	}
 | 
        
           |  |  | 126 | 	else{
 | 
        
           | 114 | cycrow | 127 | 		if(bDirectOutput){
 | 
        
           | 1 | cycrow | 128 | 			size_t endPos=os->tell();
 | 
        
           | 114 | cycrow | 129 | 			os->seek(pathCountOffset, mystream::stream_base::seek_begin);
 | 
        
           | 1 | cycrow | 130 | 			*os << pathCount;
 | 
        
           | 114 | cycrow | 131 | 			os->seek((int)endPos, mystream::stream_base::seek_begin);
 | 
        
           | 1 | cycrow | 132 | 		}
 | 
        
           |  |  | 133 | 		return cut;
 | 
        
           |  |  | 134 | 	}
 | 
        
           |  |  | 135 | }
 | 
        
           |  |  | 136 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 137 | bob_path * bod_cut_parser::loadPath(bob_dom_cut *cut, token_stream& is)
 | 
        
           | 1 | cycrow | 138 | {
 | 
        
           | 114 | cycrow | 139 | 	bob_path *path=cut->createChild();
 | 
        
           | 1 | cycrow | 140 |   | 
        
           |  |  | 141 | 	bool bRes=false;
 | 
        
           | 114 | cycrow | 142 |   | 
        
           | 1 | cycrow | 143 | 	bod_text_parser::token *t;
 | 
        
           | 114 | cycrow | 144 |   | 
        
           | 1 | cycrow | 145 | 	do{
 | 
        
           |  |  | 146 | 		t=is.tok();
 | 
        
           | 114 | cycrow | 147 |   | 
        
           | 1 | cycrow | 148 | 		// index
 | 
        
           |  |  | 149 | 		if(t==NULL || t->type!=token::t_text || strcmp(t->text, "P")!=0)
 | 
        
           |  |  | 150 | 			{ error(t ? t : is.previous(), S_Error, "Expected body declaration starting with Path ID (P)."); break; }
 | 
        
           |  |  | 151 | 		if((t=loadValue(++is))==NULL)
 | 
        
           |  |  | 152 | 			break;
 | 
        
           |  |  | 153 | 		if(!isinteger(t->text))
 | 
        
           |  |  | 154 | 			{ error(t, S_Error, "Body declaration: Expected number after '%s'", is.previous()->text); break; }
 | 
        
           |  |  | 155 | 		else
 | 
        
           |  |  | 156 | 			path->partIdx=atoi(t->text);
 | 
        
           | 114 | cycrow | 157 |   | 
        
           | 1 | cycrow | 158 | 		// body id
 | 
        
           |  |  | 159 | 		t=is.tok();
 | 
        
           |  |  | 160 | 		if(t==NULL || t->type!=token::t_text || strcmp(t->text, "B")!=0)
 | 
        
           |  |  | 161 | 			{ error(t ? t : is.previous(), S_Error, "Body declaration: Expected Body ID (B)."); break; }
 | 
        
           |  |  | 162 | 		if((t=loadValue(++is))==NULL)
 | 
        
           |  |  | 163 | 			break;
 | 
        
           |  |  | 164 | 		if(cut->version < 6 && !isinteger(t->text)) {
 | 
        
           |  |  | 165 | 			error(t, S_Error, "Body declaration: body ID is string but cut version is %d. Change version to 6.", cut->version);
 | 
        
           |  |  | 166 | 			break;
 | 
        
           |  |  | 167 | 		}
 | 
        
           |  |  | 168 | 		path->bodyId(t->text);
 | 
        
           | 114 | cycrow | 169 |   | 
        
           | 1 | cycrow | 170 | 		bRes=true;
 | 
        
           | 114 | cycrow | 171 |   | 
        
           | 1 | cycrow | 172 | 		bool bCockpit=false, bParentIdx=false, bName=false, bNotes=false;
 | 
        
           | 114 | cycrow | 173 |   | 
        
           | 1 | cycrow | 174 | 		// cockpit, name, flag, body flag, inner bob, notes
 | 
        
           |  |  | 175 | 		while(is.good()){
 | 
        
           |  |  | 176 | 			t=is.tok();
 | 
        
           | 114 | cycrow | 177 | 			if(t->type==token::t_openCrBracket)
 | 
        
           | 1 | cycrow | 178 | 				break;
 | 
        
           | 114 | cycrow | 179 |   | 
        
           | 1 | cycrow | 180 | 			if(t->type!=token::t_text || strlen(t->text) > 1){
 | 
        
           |  |  | 181 | 				error(t, S_Error, "Unexpected here: '%s'", t->getText());
 | 
        
           |  |  | 182 | 				bRes=false;
 | 
        
           |  |  | 183 | 				break;
 | 
        
           |  |  | 184 | 			}
 | 
        
           | 114 | cycrow | 185 |   | 
        
           | 1 | cycrow | 186 | 			char ch=t->text[0];
 | 
        
           | 114 | cycrow | 187 |   | 
        
           | 1 | cycrow | 188 | 			// cockpit index
 | 
        
           |  |  | 189 | 			if(ch=='C'){
 | 
        
           |  |  | 190 | 				if((t=loadValue(++is))==NULL)
 | 
        
           |  |  | 191 | 					{ bRes=false; break; }
 | 
        
           |  |  | 192 | 				if(!isinteger(t->text))
 | 
        
           |  |  | 193 | 					{ error(t, S_Error, "Body declaration: Expected number after '%s'", is.previous()->text); bRes=false; break; }
 | 
        
           | 114 | cycrow | 194 |   | 
        
           | 1 | cycrow | 195 | 				if(bCockpit)
 | 
        
           |  |  | 196 | 					error(t, S_Warning, "Cockpit index already defined, last value will be used");
 | 
        
           | 114 | cycrow | 197 |   | 
        
           | 1 | cycrow | 198 | 				bCockpit=true;
 | 
        
           |  |  | 199 | 				path->cockpitIdx=atoi(t->text);
 | 
        
           |  |  | 200 | 			}
 | 
        
           |  |  | 201 | 			// parent index
 | 
        
           |  |  | 202 | 			else if(ch=='F'){
 | 
        
           |  |  | 203 | 				if((t=loadValue(++is))==NULL)
 | 
        
           |  |  | 204 | 					{ bRes=false; break; }
 | 
        
           |  |  | 205 | 				if(!isinteger(t->text))
 | 
        
           |  |  | 206 | 					{ error(t, S_Error, "Body declaration: Expected number after '%s'", is.previous()->text); bRes=false; break; }
 | 
        
           | 114 | cycrow | 207 |   | 
        
           | 1 | cycrow | 208 | 				if(bParentIdx)
 | 
        
           |  |  | 209 | 					error(t, S_Warning, "Parent index already defined, last value will be used");
 | 
        
           | 114 | cycrow | 210 |   | 
        
           | 1 | cycrow | 211 | 				bParentIdx=true;
 | 
        
           |  |  | 212 | 				path->parentIdx=atoi(t->text);
 | 
        
           |  |  | 213 | 			}
 | 
        
           |  |  | 214 | 			// name
 | 
        
           |  |  | 215 | 			else if(ch=='N'){
 | 
        
           |  |  | 216 | 				const char *name=loadString(++is);
 | 
        
           |  |  | 217 | 				if(name==0) break;
 | 
        
           | 114 | cycrow | 218 |   | 
        
           | 1 | cycrow | 219 | 				if(bName)
 | 
        
           |  |  | 220 | 					error(t, S_Warning, "Name already defined, last value will be used");
 | 
        
           | 114 | cycrow | 221 |   | 
        
           | 1 | cycrow | 222 | 				bName=true;
 | 
        
           |  |  | 223 | 				path->name.m_text=(char*)name;
 | 
        
           |  |  | 224 | 			}
 | 
        
           |  |  | 225 | 			// embedded bob
 | 
        
           |  |  | 226 | 			else if(ch=='L'){
 | 
        
           |  |  | 227 | 				t=(++is).tok();
 | 
        
           | 114 | cycrow | 228 | 				if(t==NULL || t->type!=token::t_openCrBracket)
 | 
        
           | 1 | cycrow | 229 | 					{ error(t ? t : is.previous(), S_Error, "Expected beginning of block after '%s'", is.previous()->getText()); bRes=false; break; }
 | 
        
           |  |  | 230 | 				else{
 | 
        
           |  |  | 231 | 					++is;
 | 
        
           |  |  | 232 | 					path->bob=loadBOB(is, true);
 | 
        
           |  |  | 233 | 					if(path->bob==NULL) {
 | 
        
           |  |  | 234 | 						bRes=false; break;
 | 
        
           |  |  | 235 | 					}
 | 
        
           |  |  | 236 | 				}
 | 
        
           |  |  | 237 | 			}
 | 
        
           |  |  | 238 | 			// notes
 | 
        
           |  |  | 239 | 			else if(ch=='T'){
 | 
        
           | 114 | cycrow | 240 | 				if(loadNote(path, is)==false)
 | 
        
           | 1 | cycrow | 241 | 					{ bRes=false; break; }
 | 
        
           | 114 | cycrow | 242 |   | 
        
           | 1 | cycrow | 243 | 				if(bNotes)
 | 
        
           |  |  | 244 | 					error(t, S_Warning, "Notes already defined, last definition will be used");
 | 
        
           | 114 | cycrow | 245 |   | 
        
           | 1 | cycrow | 246 | 				bNotes=true;
 | 
        
           |  |  | 247 | 			}
 | 
        
           |  |  | 248 | 			// constants
 | 
        
           |  |  | 249 | 			else if(ch=='K'){
 | 
        
           |  |  | 250 | 				int count;
 | 
        
           | 114 | cycrow | 251 | 				bob_constants::constant c;
 | 
        
           |  |  | 252 |   | 
        
           | 1 | cycrow | 253 | 				if(!loadIntValue(++is, &count)){
 | 
        
           |  |  | 254 | 					bRes=false; break;
 | 
        
           |  |  | 255 | 				}
 | 
        
           |  |  | 256 | 				for(int i=0; i < count; i++){
 | 
        
           |  |  | 257 | 					loadIntValue(is, &(c.a));
 | 
        
           |  |  | 258 | 					if(!loadDoubleValue(is, &(c.b))){
 | 
        
           |  |  | 259 | 						bRes=false; break;
 | 
        
           |  |  | 260 | 					}
 | 
        
           |  |  | 261 | 					path->constants.values.push_back(c);
 | 
        
           |  |  | 262 | 				}
 | 
        
           | 114 | cycrow | 263 | 				if(bRes==false) break;
 | 
        
           | 1 | cycrow | 264 | 			}
 | 
        
           |  |  | 265 | 			// last try if it's a body flag (Camera, Light, Direct, v). It must not be followed by semicolon
 | 
        
           |  |  | 266 | 			else{
 | 
        
           |  |  | 267 | 				t=(++is).tok();
 | 
        
           |  |  | 268 | 				if(t){
 | 
        
           |  |  | 269 | 					if(t->type==token::t_semicolon)
 | 
        
           |  |  | 270 | 						{ error(t, S_Error, "Invalid Body flag specification '%s': flag must NOT be followed by ';'", is.previous()->text); bRes=false; break; }
 | 
        
           |  |  | 271 | 					if(t->type==token::t_colon)
 | 
        
           |  |  | 272 | 						{ error(t, S_Error, "Unexpected here: ':'"); bRes=false; break; }
 | 
        
           |  |  | 273 | 				}
 | 
        
           |  |  | 274 | 				if(!(ch >='a' && ch<='z' || ch>='A' && ch<='Z'))
 | 
        
           |  |  | 275 | 					{ error(is.previous(), S_Error, "Invalid Body flag specification '%c': flag must be alphabetic character", ch); bRes=false; break; }
 | 
        
           |  |  | 276 | 				if(ch!='c' && ch!='l' && ch!='d' && ch!='v' && ch!='b' && ch!='j' && ch!='u')
 | 
        
           |  |  | 277 | 					{ error(is.previous(), S_Warning, "Body flag '%c' out of safe limits, known values are 'c', 'l', 's', 'v', 'p', 'j', 'u'", ch); }
 | 
        
           | 114 | cycrow | 278 |   | 
        
           | 1 | cycrow | 279 | 				//path->bodyFlag=ch - 'b';
 | 
        
           |  |  | 280 | 				/*
 | 
        
           |  |  | 281 | 					TODO: translate the char into body flag and
 | 
        
           |  |  | 282 | 					OR the flags together
 | 
        
           | 114 | cycrow | 283 |   | 
        
           | 1 | cycrow | 284 | 				*/
 | 
        
           |  |  | 285 | 				/*
 | 
        
           |  |  | 286 | 					if(bodyFlags & BodyFlags::fBody)
 | 
        
           |  |  | 287 | 					os << "b ";
 | 
        
           |  |  | 288 | 					if(bodyFlags & BodyFlags::fScene)
 | 
        
           |  |  | 289 | 						os << "j ";
 | 
        
           |  |  | 290 | 					int i=bodyFlags & 0x3F;
 | 
        
           | 114 | cycrow | 291 | 					if(i)
 | 
        
           | 1 | cycrow | 292 | 						os << (char) ('b' + i) << ' ';
 | 
        
           |  |  | 293 | 				*/
 | 
        
           |  |  | 294 | 				switch(ch){
 | 
        
           |  |  | 295 | 					// both probably mean 'scene'
 | 
        
           |  |  | 296 | 					case 'j': // no break
 | 
        
           |  |  | 297 | 					case 'u':
 | 
        
           | 114 | cycrow | 298 | 						path->bodyFlags|=bob_path::fScene;
 | 
        
           | 1 | cycrow | 299 | 						break;
 | 
        
           |  |  | 300 | 					case 'b':
 | 
        
           | 114 | cycrow | 301 | 						path->bodyFlags|=bob_path::fBody;
 | 
        
           | 1 | cycrow | 302 | 						break;
 | 
        
           |  |  | 303 | 					default:
 | 
        
           |  |  | 304 | 						path->bodyFlags|=ch - 'b';
 | 
        
           |  |  | 305 | 				}
 | 
        
           |  |  | 306 | 			}
 | 
        
           |  |  | 307 | 		}
 | 
        
           |  |  | 308 | 	}
 | 
        
           |  |  | 309 | 	while(false);
 | 
        
           | 114 | cycrow | 310 |   | 
        
           |  |  | 311 | 	if(bRes && t && t->type!=token::t_openCrBracket)
 | 
        
           | 1 | cycrow | 312 | 		{ error(is.previous(), S_Error, "Unexpected end of document found when looking for beginning of Frame block"); bRes=false; }
 | 
        
           | 114 | cycrow | 313 |   | 
        
           | 1 | cycrow | 314 | 	if(bRes==false){
 | 
        
           |  |  | 315 | 		cut->removeChild(cut->end() - 1);
 | 
        
           |  |  | 316 | 		path=NULL;
 | 
        
           |  |  | 317 | 	}
 | 
        
           | 114 | cycrow | 318 |   | 
        
           | 1 | cycrow | 319 | 	return path;
 | 
        
           |  |  | 320 | }
 | 
        
           |  |  | 321 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 322 | bool bod_cut_parser::loadNote(bob_path *path, token_stream& is)
 | 
        
           | 1 | cycrow | 323 | {
 | 
        
           |  |  | 324 | 	bob_note *n;
 | 
        
           |  |  | 325 | 	bod_text_parser::token *t;
 | 
        
           |  |  | 326 | 	bool bEnd=false;
 | 
        
           | 114 | cycrow | 327 |   | 
        
           | 1 | cycrow | 328 | 	path->notes().removeChildren();
 | 
        
           | 114 | cycrow | 329 |   | 
        
           | 1 | cycrow | 330 | 	++is;
 | 
        
           |  |  | 331 | 	do{
 | 
        
           |  |  | 332 | 		n=path->notes().createChild();
 | 
        
           |  |  | 333 | 		// left
 | 
        
           |  |  | 334 | 		if((t=loadValue(is))==NULL)
 | 
        
           |  |  | 335 | 			break;
 | 
        
           |  |  | 336 | 		if(!isinteger(t->text))
 | 
        
           |  |  | 337 | 			{ error(t, S_Error, "Expected number"); break; }
 | 
        
           |  |  | 338 | 		n->value=atoi(t->text);
 | 
        
           | 114 | cycrow | 339 |   | 
        
           |  |  | 340 | 		if(n->value==-1) {
 | 
        
           | 1 | cycrow | 341 | 			path->notes().removeChild(path->notes().end() - 1);
 | 
        
           |  |  | 342 | 			bEnd=true;
 | 
        
           |  |  | 343 | 			break; // end of notes
 | 
        
           |  |  | 344 | 		}
 | 
        
           | 114 | cycrow | 345 |   | 
        
           |  |  | 346 | 		// right
 | 
        
           | 1 | cycrow | 347 | 		n->text=loadString(is);
 | 
        
           |  |  | 348 | 		if(n->text==NULL){
 | 
        
           |  |  | 349 | 			path->notes().removeChild(path->notes().end() - 1);
 | 
        
           |  |  | 350 | 			break;
 | 
        
           |  |  | 351 | 		}
 | 
        
           |  |  | 352 | 	}
 | 
        
           |  |  | 353 | 	while(is.good());
 | 
        
           | 114 | cycrow | 354 |   | 
        
           | 1 | cycrow | 355 | 	if(bEnd==false && is.eof())
 | 
        
           |  |  | 356 | 		error(is.previous(), S_Error, "Unexpected end of document found while looking for end of Notes (-1)");
 | 
        
           | 114 | cycrow | 357 |   | 
        
           | 1 | cycrow | 358 | 	return t!=NULL;
 | 
        
           |  |  | 359 | }
 | 
        
           |  |  | 360 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 361 | bool bod_cut_parser::loadFrame(bob_path *path, token_stream& is)
 | 
        
           | 1 | cycrow | 362 | {
 | 
        
           |  |  | 363 | 	token *t;
 | 
        
           |  |  | 364 | 	bool bRes=false;
 | 
        
           | 114 | cycrow | 365 |   | 
        
           |  |  | 366 | 	bob_frame *frame=path->createChild();
 | 
        
           | 1 | cycrow | 367 | 	int flags;
 | 
        
           | 114 | cycrow | 368 |   | 
        
           | 1 | cycrow | 369 | 	// frame flags
 | 
        
           |  |  | 370 | 	t=is.tok();
 | 
        
           |  |  | 371 | 	if(t==NULL)
 | 
        
           | 114 | cycrow | 372 | 		error(is.previous(), S_Error, "Expected frame ID");
 | 
        
           | 1 | cycrow | 373 | 	else if(loadValue(is)){
 | 
        
           |  |  | 374 | 		if(!(isinteger(t->text) || ishexa(t->text)))
 | 
        
           |  |  | 375 | 			error(t, S_Error, "Expected frame ID in decadic or hexadecimal format");
 | 
        
           |  |  | 376 | 		else{
 | 
        
           |  |  | 377 | 			if(t->text[0]=='0' && ((t->text[1] | 0x20) == 'x'))
 | 
        
           |  |  | 378 | 				flags=hextoi(t->text);
 | 
        
           |  |  | 379 | 			else
 | 
        
           |  |  | 380 | 				flags=atoi(t->text);
 | 
        
           | 114 | cycrow | 381 |   | 
        
           | 1 | cycrow | 382 | 			if(flags & CUT_F_POSBEZINFO)
 | 
        
           |  |  | 383 | 				error(NULL, S_Warning, "CUT_F_POSBEZINFO encoutered - don't know how to compile");
 | 
        
           |  |  | 384 | 			if(flags & CUT_F_SAMESCALE)
 | 
        
           |  |  | 385 | 				error(NULL, S_Warning, "CUT_F_SAMESCALE encoutered");
 | 
        
           | 114 | cycrow | 386 |   | 
        
           |  |  | 387 | 			if(flags & ~bob_frame::flagMask)
 | 
        
           | 1 | cycrow | 388 | 				error(is.tok(), S_Warning, "Unsupported bits set in frame flags - normalizing flags, unsupported values will not be compiled");
 | 
        
           | 114 | cycrow | 389 |   | 
        
           |  |  | 390 | 			flags&=bob_frame::flagMask;
 | 
        
           | 1 | cycrow | 391 | 			frame->flags=flags;
 | 
        
           | 114 | cycrow | 392 |   | 
        
           | 1 | cycrow | 393 | 			bRes=true;
 | 
        
           |  |  | 394 | 		}
 | 
        
           |  |  | 395 | 	}
 | 
        
           | 114 | cycrow | 396 |   | 
        
           | 1 | cycrow | 397 | 	while(bRes){
 | 
        
           |  |  | 398 | 		static const char *pos_context = "frame: position: ";
 | 
        
           |  |  | 399 | 		static const char *rot_context ="frame: rotation: ";
 | 
        
           |  |  | 400 | 		static const char *tpos_context ="frame: target position: ";
 | 
        
           |  |  | 401 | 		static const char *troll_context ="frame: roll angle: ";
 | 
        
           |  |  | 402 | 		static const char *fov_context ="frame: FOV: ";
 | 
        
           |  |  | 403 | 		static const char *color_context ="frame: RGB: ";
 | 
        
           |  |  | 404 | 		static const char *len_context ="frame: length: ";
 | 
        
           |  |  | 405 | 		static const char *idx_context ="frame: index: ";
 | 
        
           | 114 | cycrow | 406 |   | 
        
           | 1 | cycrow | 407 | 		if((flags & CUT_F_SAMEPOS)==0){
 | 
        
           |  |  | 408 | 			loadIntValue(is, &(frame->position.x), pos_context);
 | 
        
           |  |  | 409 | 			loadIntValue(is, &(frame->position.y), pos_context);
 | 
        
           |  |  | 410 | 			if((bRes=loadIntValue(is, &(frame->position.z), pos_context))==false) break;
 | 
        
           | 114 | cycrow | 411 |   | 
        
           | 1 | cycrow | 412 | 			if(flags & CUT_F_POSTCBINFO) {
 | 
        
           | 114 | cycrow | 413 | 				frame->pos_tcb_info=new bob_frame::tcb_info();
 | 
        
           | 1 | cycrow | 414 | 				if((bRes=loadTCBInfo(is, frame->pos_tcb_info))==false) break;
 | 
        
           |  |  | 415 | 			}
 | 
        
           |  |  | 416 | 		}
 | 
        
           |  |  | 417 | 		if((flags & CUT_F_SAMEROT)==0 && (flags & CUT_F_ROT)){
 | 
        
           | 114 | cycrow | 418 | 			frame->rotation=new bob_frame::AngleAxis();
 | 
        
           | 1 | cycrow | 419 | 			loadDoubleValue(is, &(frame->rotation->angle), rot_context);
 | 
        
           |  |  | 420 | 			loadDoubleValue(is, &(frame->rotation->x), rot_context);
 | 
        
           |  |  | 421 | 			loadDoubleValue(is, &(frame->rotation->y), rot_context);
 | 
        
           |  |  | 422 | 			if((bRes=loadDoubleValue(is, &(frame->rotation->z), rot_context))==false) break;
 | 
        
           | 114 | cycrow | 423 |   | 
        
           | 1 | cycrow | 424 | 			if(flags & CUT_F_ROTTCBINFO){
 | 
        
           | 114 | cycrow | 425 | 				frame->rot_tcb_info=new bob_frame::tcb_info();
 | 
        
           | 1 | cycrow | 426 | 				if((bRes=loadTCBInfo(is, frame->rot_tcb_info))==false) break;
 | 
        
           |  |  | 427 | 			}
 | 
        
           |  |  | 428 | 		}
 | 
        
           |  |  | 429 | 		if(flags & CUT_F_TARGETPOS){
 | 
        
           |  |  | 430 | 			if((flags & CUT_F_SAMETARGET)==0){
 | 
        
           | 114 | cycrow | 431 | 				frame->targetPos=new bob_frame::Position();
 | 
        
           | 1 | cycrow | 432 | 				loadIntValue(is, &(frame->targetPos->x), tpos_context);
 | 
        
           |  |  | 433 | 				loadIntValue(is, &(frame->targetPos->y), tpos_context);
 | 
        
           |  |  | 434 | 				if((bRes=loadIntValue(is, &(frame->targetPos->z), tpos_context))==false) break;
 | 
        
           |  |  | 435 | 			}
 | 
        
           |  |  | 436 | 			if((flags & CUT_F_SAMEROT)==0){
 | 
        
           |  |  | 437 | 				if((bRes=loadDoubleValue(is, &(frame->rollAngle), troll_context))==false) break;
 | 
        
           |  |  | 438 | 			}
 | 
        
           |  |  | 439 | 			if(flags & CUT_F_TPOSTCBINFO){
 | 
        
           | 114 | cycrow | 440 | 				frame->tpos_tcb_info=new bob_frame::tcb_info();
 | 
        
           | 1 | cycrow | 441 | 				if((bRes=loadTCBInfo(is, frame->tpos_tcb_info))==false) break;
 | 
        
           |  |  | 442 | 			}
 | 
        
           |  |  | 443 | 		}
 | 
        
           |  |  | 444 | 		if((flags & CUT_F_SAMEFOV)==0 && flags & CUT_F_FOV){
 | 
        
           |  |  | 445 | 			if((bRes=loadDoubleValue(is, &(frame->fov), fov_context))==false) break;
 | 
        
           |  |  | 446 | 		}
 | 
        
           |  |  | 447 | 		if((flags & CUT_F_SAMECOLOR)==0 && flags & CUT_F_COLOR){
 | 
        
           | 114 | cycrow | 448 | 			frame->color=new bob_frame::rgb();
 | 
        
           | 1 | cycrow | 449 | 			loadDoubleValue(is, &(frame->color->r), color_context);
 | 
        
           |  |  | 450 | 			loadDoubleValue(is, &(frame->color->r), color_context);
 | 
        
           |  |  | 451 | 			if((bRes=loadDoubleValue(is, &(frame->color->r), color_context))==false) break;
 | 
        
           |  |  | 452 | 		}
 | 
        
           |  |  | 453 | 		if((bRes=loadIntValue(is, &(frame->length), len_context))==false) break;
 | 
        
           |  |  | 454 | 		if((bRes=loadIntValue(is, &(frame->index), idx_context))==false) break;
 | 
        
           | 114 | cycrow | 455 |   | 
        
           | 1 | cycrow | 456 | 		break;
 | 
        
           |  |  | 457 | 	}
 | 
        
           |  |  | 458 | 	if(bRes){
 | 
        
           |  |  | 459 | 		int c=0;
 | 
        
           | 114 | cycrow | 460 | 		while((t=is.tok()) && t->type!=token::t_closeCrBracket){
 | 
        
           | 1 | cycrow | 461 | 			c++;
 | 
        
           |  |  | 462 | 			if(loadValue(is)==false) break;
 | 
        
           |  |  | 463 | 		}
 | 
        
           |  |  | 464 | 		if(t==NULL){
 | 
        
           |  |  | 465 | 			error(is.previous(), S_Error, "Unexpected end of document found while looking for end of frame block '}'");
 | 
        
           |  |  | 466 | 		}
 | 
        
           |  |  | 467 | 		else if(c > 0){
 | 
        
           |  |  | 468 | 			error(is.tok(), S_Warning, "Too many values in frame block: %d (expected %d), they will be discarded", frame->valueCount() + 2, frame->valueCount() + 2 + c);
 | 
        
           |  |  | 469 | 		}
 | 
        
           |  |  | 470 | 		++is; // past the end bracket
 | 
        
           |  |  | 471 | 	}
 | 
        
           |  |  | 472 | 	else{
 | 
        
           | 114 | cycrow | 473 | 		if(is.tok() && is.tok()->type==token::t_closeCrBracket)
 | 
        
           | 1 | cycrow | 474 | 			error(is.tok(), S_Error, "Premature end of frame block encountered. Expected %d values (+frame flags)", frame->valueCount() + 2);
 | 
        
           |  |  | 475 | 	}
 | 
        
           |  |  | 476 | 	return bRes;
 | 
        
           |  |  | 477 | }
 | 
        
           |  |  | 478 | //---------------------------------------------------------------------------------
 | 
        
           | 114 | cycrow | 479 | bool bod_cut_parser::loadTCBInfo(token_stream& is, bob_frame::tcb_info *info)
 | 
        
           | 1 | cycrow | 480 | {
 | 
        
           |  |  | 481 | 	if(!loadDoubleValue(is, &(info->tension), "TCB info (tension): ")) return false;
 | 
        
           |  |  | 482 | 	if(!loadDoubleValue(is, &(info->continuity), "TCB info (continuity): ")) return false;
 | 
        
           |  |  | 483 | 	if(!loadDoubleValue(is, &(info->bias), "TCB info (bias): ")) return false;
 | 
        
           |  |  | 484 | 	if(!loadDoubleValue(is, &(info->easeFrom), "TCB info (ease from): ")) return false;
 | 
        
           |  |  | 485 | 	if(!loadDoubleValue(is, &(info->easeTo), "TCB info (ease to): ")) return false;
 | 
        
           |  |  | 486 | 	return true;
 | 
        
           |  |  | 487 | }
 | 
        
           |  |  | 488 | //---------------------------------------------------------------------------------
 |