| 1 | cycrow | 1 | #include "bod_cut_parser.h"
 | 
        
           |  |  | 2 | #include "../common/strutils.h"
 | 
        
           |  |  | 3 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 4 | bool bod_cut_parser::compile(token_stream& is, bob_dom_obinaryfilestream& os)
 | 
        
           |  |  | 5 | {
 | 
        
           |  |  | 6 | 	os << bob_dom_cut::hdr_begin;
 | 
        
           |  |  | 7 |   | 
        
           |  |  | 8 | 	bob_dom_cut *cut=loadCUT(is, &os, true);
 | 
        
           |  |  | 9 |   | 
        
           |  |  | 10 | 	//if(cut)
 | 
        
           |  |  | 11 | 		//cut->toFile(os);
 | 
        
           |  |  | 12 |   | 
        
           |  |  | 13 | 	delete cut;
 | 
        
           |  |  | 14 |   | 
        
           |  |  | 15 | 	os << bob_dom_cut::hdr_end;
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | 	return cut!=NULL;
 | 
        
           |  |  | 18 | }
 | 
        
           |  |  | 19 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 20 | bob_dom_cut * bod_cut_parser::loadCUT(token_stream& is)
 | 
        
           |  |  | 21 | {
 | 
        
           |  |  | 22 | 	bob_dom_obinaryfilestream *dummy=0;
 | 
        
           |  |  | 23 |   | 
        
           |  |  | 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
 | 
        
           |  |  | 29 | bob_dom_cut * bod_cut_parser::loadCUT(token_stream& is, bob_dom_obinaryfilestream *os, bool bDirectOutput)
 | 
        
           |  |  | 30 | {
 | 
        
           |  |  | 31 | 	bod_text_parser::token *t;
 | 
        
           |  |  | 32 | 	bob_dom_path *actPath=0;
 | 
        
           |  |  | 33 | 	bob_dom_stat *actStat=0;
 | 
        
           |  |  | 34 | 	bob_dom_cut *cut=new bob_dom_cut(m_settings);
 | 
        
           |  |  | 35 |   | 
        
           |  |  | 36 | 	// used for direct output
 | 
        
           |  |  | 37 | 	int pathCountOffset;
 | 
        
           |  |  | 38 | 	int pathCount=0;
 | 
        
           |  |  | 39 |   | 
        
           |  |  | 40 | 	bool bErrors=false;
 | 
        
           |  |  | 41 | 	bool bRes=false;
 | 
        
           |  |  | 42 |   | 
        
           |  |  | 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; }
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 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; }
 | 
        
           |  |  | 59 |   | 
        
           |  |  | 60 | 		if(!checkImmediatePlacement(is.previous(), is.tok())) 
 | 
        
           |  |  | 61 | 			break;
 | 
        
           |  |  | 62 |   | 
        
           |  |  | 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; }
 | 
        
           |  |  | 67 |   | 
        
           |  |  | 68 | 		cut->version=atoi(t->text);
 | 
        
           |  |  | 69 |   | 
        
           |  |  | 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);
 | 
        
           |  |  | 72 |   | 
        
           |  |  | 73 | 		if(bDirectOutput){
 | 
        
           |  |  | 74 | 			cut->info.toFile(*os);
 | 
        
           |  |  | 75 | 			*os << cut->version; 
 | 
        
           |  |  | 76 | 			/*	
 | 
        
           |  |  | 77 | 				we must output the path count right now, 
 | 
        
           |  |  | 78 | 				but we will rewrite it once we finish
 | 
        
           |  |  | 79 | 			*/
 | 
        
           |  |  | 80 | 			pathCountOffset=(int)os->tell();
 | 
        
           |  |  | 81 | 			*os << pathCount; 
 | 
        
           |  |  | 82 | 		}
 | 
        
           |  |  | 83 |   | 
        
           |  |  | 84 | 		while(is.good()){
 | 
        
           |  |  | 85 | 			t=is.tok();
 | 
        
           |  |  | 86 |   | 
        
           |  |  | 87 | 			if(t->type==token::t_openBracket){
 | 
        
           |  |  | 88 | 				if(actPath==NULL){
 | 
        
           |  |  | 89 | 					error(t, S_Error, "Block unexpected here.");
 | 
        
           |  |  | 90 | 					break;
 | 
        
           |  |  | 91 | 				}
 | 
        
           |  |  | 92 | 				else{
 | 
        
           |  |  | 93 | 					bErrors|=!loadFrame(actPath, ++is); 
 | 
        
           |  |  | 94 | 				}
 | 
        
           |  |  | 95 | 			}
 | 
        
           |  |  | 96 |   | 
        
           |  |  | 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;
 | 
        
           |  |  | 105 |   | 
        
           |  |  | 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);
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 | 	if(actPath && bDirectOutput){
 | 
        
           |  |  | 117 | 		pathCount++;
 | 
        
           |  |  | 118 | 		actPath->toFile(*os, cut->version);
 | 
        
           |  |  | 119 | 		cut->removeChild(--cut->end());
 | 
        
           |  |  | 120 | 	}
 | 
        
           |  |  | 121 |   | 
        
           |  |  | 122 | 	if(bRes==false){
 | 
        
           |  |  | 123 | 		delete cut;
 | 
        
           |  |  | 124 | 		return NULL;
 | 
        
           |  |  | 125 | 	}
 | 
        
           |  |  | 126 | 	else{
 | 
        
           |  |  | 127 | 		if(bDirectOutput){	
 | 
        
           |  |  | 128 | 			size_t endPos=os->tell();
 | 
        
           |  |  | 129 | 			os->seek(pathCountOffset, bob_filestream::seek_begin);
 | 
        
           |  |  | 130 | 			*os << pathCount;
 | 
        
           |  |  | 131 | 			os->seek((int)endPos, bob_filestream::seek_begin);
 | 
        
           |  |  | 132 | 		}
 | 
        
           |  |  | 133 | 		return cut;
 | 
        
           |  |  | 134 | 	}
 | 
        
           |  |  | 135 | }
 | 
        
           |  |  | 136 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 137 | bob_dom_path * bod_cut_parser::loadPath(bob_dom_cut *cut, token_stream& is)
 | 
        
           |  |  | 138 | {
 | 
        
           |  |  | 139 | 	bob_dom_path *path=cut->createChild();
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 | 	bool bRes=false;
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 | 	bod_text_parser::token *t;
 | 
        
           |  |  | 144 |   | 
        
           |  |  | 145 | 	do{
 | 
        
           |  |  | 146 | 		t=is.tok();
 | 
        
           |  |  | 147 |   | 
        
           |  |  | 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);
 | 
        
           |  |  | 157 |   | 
        
           |  |  | 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);
 | 
        
           |  |  | 169 |   | 
        
           |  |  | 170 | 		bRes=true;
 | 
        
           |  |  | 171 |   | 
        
           |  |  | 172 | 		bool bCockpit=false, bParentIdx=false, bName=false, bNotes=false;
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 | 		// cockpit, name, flag, body flag, inner bob, notes
 | 
        
           |  |  | 175 | 		while(is.good()){
 | 
        
           |  |  | 176 | 			t=is.tok();
 | 
        
           |  |  | 177 | 			if(t->type==token::t_openBracket)
 | 
        
           |  |  | 178 | 				break;
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 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 | 			}
 | 
        
           |  |  | 185 |   | 
        
           |  |  | 186 | 			char ch=t->text[0];
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 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; }
 | 
        
           |  |  | 194 |   | 
        
           |  |  | 195 | 				if(bCockpit)
 | 
        
           |  |  | 196 | 					error(t, S_Warning, "Cockpit index already defined, last value will be used");
 | 
        
           |  |  | 197 |   | 
        
           |  |  | 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; }
 | 
        
           |  |  | 207 |   | 
        
           |  |  | 208 | 				if(bParentIdx)
 | 
        
           |  |  | 209 | 					error(t, S_Warning, "Parent index already defined, last value will be used");
 | 
        
           |  |  | 210 |   | 
        
           |  |  | 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;
 | 
        
           |  |  | 218 |   | 
        
           |  |  | 219 | 				if(bName)
 | 
        
           |  |  | 220 | 					error(t, S_Warning, "Name already defined, last value will be used");
 | 
        
           |  |  | 221 |   | 
        
           |  |  | 222 | 				bName=true;
 | 
        
           |  |  | 223 | 				path->name.m_text=(char*)name;
 | 
        
           |  |  | 224 | 			}
 | 
        
           |  |  | 225 | 			// embedded bob
 | 
        
           |  |  | 226 | 			else if(ch=='L'){
 | 
        
           |  |  | 227 | 				t=(++is).tok();
 | 
        
           |  |  | 228 | 				if(t==NULL || t->type!=token::t_openBracket)
 | 
        
           |  |  | 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'){
 | 
        
           |  |  | 240 | 				if(loadNote(path, is)==false) 
 | 
        
           |  |  | 241 | 					{ bRes=false; break; }
 | 
        
           |  |  | 242 |   | 
        
           |  |  | 243 | 				if(bNotes)
 | 
        
           |  |  | 244 | 					error(t, S_Warning, "Notes already defined, last definition will be used");
 | 
        
           |  |  | 245 |   | 
        
           |  |  | 246 | 				bNotes=true;
 | 
        
           |  |  | 247 | 			}
 | 
        
           |  |  | 248 | 			// constants
 | 
        
           |  |  | 249 | 			else if(ch=='K'){
 | 
        
           |  |  | 250 | 				int count;
 | 
        
           |  |  | 251 | 				bob_dom_constants::constant c;
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 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 | 				}
 | 
        
           |  |  | 263 | 				if(bRes==false) break;	
 | 
        
           |  |  | 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); }
 | 
        
           |  |  | 278 |   | 
        
           |  |  | 279 | 				//path->bodyFlag=ch - 'b';
 | 
        
           |  |  | 280 | 				/*
 | 
        
           |  |  | 281 | 					TODO: translate the char into body flag and
 | 
        
           |  |  | 282 | 					OR the flags together
 | 
        
           |  |  | 283 |   | 
        
           |  |  | 284 | 				*/
 | 
        
           |  |  | 285 | 				/*
 | 
        
           |  |  | 286 | 					if(bodyFlags & BodyFlags::fBody)
 | 
        
           |  |  | 287 | 					os << "b ";
 | 
        
           |  |  | 288 | 					if(bodyFlags & BodyFlags::fScene)
 | 
        
           |  |  | 289 | 						os << "j ";
 | 
        
           |  |  | 290 | 					int i=bodyFlags & 0x3F;
 | 
        
           |  |  | 291 | 					if(i) 
 | 
        
           |  |  | 292 | 						os << (char) ('b' + i) << ' ';
 | 
        
           |  |  | 293 | 				*/
 | 
        
           |  |  | 294 | 				switch(ch){
 | 
        
           |  |  | 295 | 					// both probably mean 'scene'
 | 
        
           |  |  | 296 | 					case 'j': // no break
 | 
        
           |  |  | 297 | 					case 'u':
 | 
        
           |  |  | 298 | 						path->bodyFlags|=bob_dom_path::fScene;
 | 
        
           |  |  | 299 | 						break;
 | 
        
           |  |  | 300 | 					case 'b':
 | 
        
           |  |  | 301 | 						path->bodyFlags|=bob_dom_path::fBody;
 | 
        
           |  |  | 302 | 						break;
 | 
        
           |  |  | 303 | 					default:
 | 
        
           |  |  | 304 | 						path->bodyFlags|=ch - 'b';
 | 
        
           |  |  | 305 | 				}
 | 
        
           |  |  | 306 | 			}
 | 
        
           |  |  | 307 | 		}
 | 
        
           |  |  | 308 | 	}
 | 
        
           |  |  | 309 | 	while(false);
 | 
        
           |  |  | 310 |   | 
        
           |  |  | 311 | 	if(bRes && t && t->type!=token::t_openBracket)
 | 
        
           |  |  | 312 | 		{ error(is.previous(), S_Error, "Unexpected end of document found when looking for beginning of Frame block"); bRes=false; }
 | 
        
           |  |  | 313 |   | 
        
           |  |  | 314 | 	if(bRes==false){
 | 
        
           |  |  | 315 | 		cut->removeChild(cut->end() - 1);
 | 
        
           |  |  | 316 | 		path=NULL;
 | 
        
           |  |  | 317 | 	}
 | 
        
           |  |  | 318 |   | 
        
           |  |  | 319 | 	return path;
 | 
        
           |  |  | 320 | }
 | 
        
           |  |  | 321 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 322 | bool bod_cut_parser::loadNote(bob_dom_path *path, token_stream& is)
 | 
        
           |  |  | 323 | {
 | 
        
           |  |  | 324 | 	bob_note *n;
 | 
        
           |  |  | 325 | 	bod_text_parser::token *t;
 | 
        
           |  |  | 326 | 	bool bEnd=false;
 | 
        
           |  |  | 327 |   | 
        
           |  |  | 328 | 	path->notes().removeChildren();
 | 
        
           |  |  | 329 |   | 
        
           |  |  | 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);
 | 
        
           |  |  | 339 |   | 
        
           |  |  | 340 | 		if(n->value==-1) {	
 | 
        
           |  |  | 341 | 			path->notes().removeChild(path->notes().end() - 1);
 | 
        
           |  |  | 342 | 			bEnd=true;
 | 
        
           |  |  | 343 | 			break; // end of notes
 | 
        
           |  |  | 344 | 		}
 | 
        
           |  |  | 345 |   | 
        
           |  |  | 346 | 		// right 
 | 
        
           |  |  | 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());
 | 
        
           |  |  | 354 |   | 
        
           |  |  | 355 | 	if(bEnd==false && is.eof())
 | 
        
           |  |  | 356 | 		error(is.previous(), S_Error, "Unexpected end of document found while looking for end of Notes (-1)");
 | 
        
           |  |  | 357 |   | 
        
           |  |  | 358 | 	return t!=NULL;
 | 
        
           |  |  | 359 | }
 | 
        
           |  |  | 360 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 361 | #ifdef X2BC_USE_INI_FORMATS
 | 
        
           |  |  | 362 | bool bod_cut_parser::loadFrame(bob_dom_path *path, token_stream& is)
 | 
        
           |  |  | 363 | {
 | 
        
           |  |  | 364 | 	token *t;
 | 
        
           |  |  | 365 | 	bool bRes=false;
 | 
        
           |  |  | 366 |   | 
        
           |  |  | 367 | 	bob_dom_stat *stat=path->createChild();
 | 
        
           |  |  | 368 | 	const Settings::StatFormat *f;
 | 
        
           |  |  | 369 |   | 
        
           |  |  | 370 | 	// frame id
 | 
        
           |  |  | 371 | 	t=is.tok();
 | 
        
           |  |  | 372 | 	if(t==NULL)
 | 
        
           |  |  | 373 | 		error(is.previous(), S_Error, "Expected frame ID"); 
 | 
        
           |  |  | 374 | 	else if(loadValue(is)){
 | 
        
           |  |  | 375 | 		if(!(isinteger(t->text) || ishexa(t->text)))
 | 
        
           |  |  | 376 | 			error(t, S_Error, "Expected frame ID in decadic or hexadecimal format");
 | 
        
           |  |  | 377 | 		else{
 | 
        
           |  |  | 378 | 			if(t->text[0]=='0' && ((t->text[1] | 0x20) == 'x'))
 | 
        
           |  |  | 379 | 				stat->frameId=hextoi(t->text);
 | 
        
           |  |  | 380 | 			else
 | 
        
           |  |  | 381 | 				stat->frameId=atoi(t->text);
 | 
        
           |  |  | 382 |   | 
        
           |  |  | 383 | 			f=m_settings->findStatFormat(stat->frameId);
 | 
        
           |  |  | 384 | 			if(f==NULL)
 | 
        
           |  |  | 385 | 				error(is.previous(), S_Error, "Cannot find frame format 0x%X - cannot continue", stat->frameId);
 | 
        
           |  |  | 386 | 			else
 | 
        
           |  |  | 387 | 				bRes=true;
 | 
        
           |  |  | 388 | 		}
 | 
        
           |  |  | 389 | 	}
 | 
        
           |  |  | 390 |   | 
        
           |  |  | 391 | 	if(bRes){
 | 
        
           |  |  | 392 | 		for(Settings::StatFormat::const_iterator &it=f->tokens.begin(); it!=f->tokens.end(); ++it){
 | 
        
           |  |  | 393 | 			for(int i=0; i < it->count; i++){
 | 
        
           |  |  | 394 | 				if((t=loadValue(is))==NULL){
 | 
        
           |  |  | 395 | 					error(is.previous(), S_Error, "Frame format 0x%X requires %d numbers", stat->frameId, f->cumulativeTokenCount);
 | 
        
           |  |  | 396 | 					bRes=false;
 | 
        
           |  |  | 397 | 					goto the_end; // yes it's a GOTO so kill me
 | 
        
           |  |  | 398 | 				}
 | 
        
           |  |  | 399 | 				if(!isfloat(t->text)){
 | 
        
           |  |  | 400 | 					error(t, S_Error, "Expected number (integer or float)"); 
 | 
        
           |  |  | 401 | 					bRes=false;
 | 
        
           |  |  | 402 | 					goto the_end;
 | 
        
           |  |  | 403 | 				}
 | 
        
           |  |  | 404 |   | 
        
           |  |  | 405 | 				if(it->numFormat->outformat==Settings::NumberFormat::Integer && !isinteger(t->text))
 | 
        
           |  |  | 406 | 					error(t, S_Warning, "Expected integer not float");
 | 
        
           |  |  | 407 |   | 
        
           |  |  | 408 | 				unsigned int v;
 | 
        
           |  |  | 409 | 				double d=(atof(t->text) / it->numFormat->multiplier);
 | 
        
           |  |  | 410 |   | 
        
           |  |  | 411 | 				// this is same as v=(unsigned int) d;
 | 
        
           |  |  | 412 | 				// but is uses normal rounding - not round toward zero, this is important 'cos otherwise there will 
 | 
        
           |  |  | 413 | 				// be error + 1 in the resulting int (only if the resulting double has fraction part)
 | 
        
           |  |  | 414 | 				__asm{
 | 
        
           |  |  | 415 | 					fld qword ptr d
 | 
        
           |  |  | 416 | 					fistp dword ptr v
 | 
        
           |  |  | 417 | 				}
 | 
        
           |  |  | 418 |   | 
        
           |  |  | 419 | 				stat->push_back(v);
 | 
        
           |  |  | 420 | 			}
 | 
        
           |  |  | 421 | 		}
 | 
        
           |  |  | 422 | 		size_t pos=is.tell();
 | 
        
           |  |  | 423 | 		while((t=is.tok()) && t->type!=token::t_closeBracket){
 | 
        
           |  |  | 424 | 			++is;
 | 
        
           |  |  | 425 | 		}
 | 
        
           |  |  | 426 | 		if(t==NULL){
 | 
        
           |  |  | 427 | 			error(is.previous(), S_Error, "Unexpected end of document found while looking for end of frame block '}'");
 | 
        
           |  |  | 428 | 			bRes=false;
 | 
        
           |  |  | 429 | 		}
 | 
        
           |  |  | 430 | 		else if(is.tell()!=pos){
 | 
        
           |  |  | 431 | 			error(is.previous(), S_Error, "Too many parameters in frame declaration, expected %d numbers", f->cumulativeTokenCount);
 | 
        
           |  |  | 432 | 			bRes=false;
 | 
        
           |  |  | 433 | 		}
 | 
        
           |  |  | 434 | 		++is; // advance past the end bracket
 | 
        
           |  |  | 435 | 	}
 | 
        
           |  |  | 436 |   | 
        
           |  |  | 437 | the_end:
 | 
        
           |  |  | 438 | 	if(bRes==false)
 | 
        
           |  |  | 439 | 		path->removeChild(path->end() - 1);
 | 
        
           |  |  | 440 | 	return bRes;
 | 
        
           |  |  | 441 | }
 | 
        
           |  |  | 442 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 443 | #else // !defined(X2BC_USE_INI_FORMATS)
 | 
        
           |  |  | 444 | bool bod_cut_parser::loadFrame(bob_dom_path *path, token_stream& is)
 | 
        
           |  |  | 445 | {
 | 
        
           |  |  | 446 | 	token *t;
 | 
        
           |  |  | 447 | 	bool bRes=false;
 | 
        
           |  |  | 448 |   | 
        
           |  |  | 449 | 	bob_dom_frame *frame=path->createChild();
 | 
        
           |  |  | 450 | 	int flags;
 | 
        
           |  |  | 451 |   | 
        
           |  |  | 452 | 	// frame flags
 | 
        
           |  |  | 453 | 	t=is.tok();
 | 
        
           |  |  | 454 | 	if(t==NULL)
 | 
        
           |  |  | 455 | 		error(is.previous(), S_Error, "Expected frame ID"); 
 | 
        
           |  |  | 456 | 	else if(loadValue(is)){
 | 
        
           |  |  | 457 | 		if(!(isinteger(t->text) || ishexa(t->text)))
 | 
        
           |  |  | 458 | 			error(t, S_Error, "Expected frame ID in decadic or hexadecimal format");
 | 
        
           |  |  | 459 | 		else{
 | 
        
           |  |  | 460 | 			if(t->text[0]=='0' && ((t->text[1] | 0x20) == 'x'))
 | 
        
           |  |  | 461 | 				flags=hextoi(t->text);
 | 
        
           |  |  | 462 | 			else
 | 
        
           |  |  | 463 | 				flags=atoi(t->text);
 | 
        
           |  |  | 464 |   | 
        
           |  |  | 465 | 			if(flags & CUT_F_POSBEZINFO)
 | 
        
           |  |  | 466 | 				error(NULL, S_Warning, "CUT_F_POSBEZINFO encoutered - don't know how to compile");
 | 
        
           |  |  | 467 | 			if(flags & CUT_F_SAMESCALE)
 | 
        
           |  |  | 468 | 				error(NULL, S_Warning, "CUT_F_SAMESCALE encoutered");
 | 
        
           |  |  | 469 |   | 
        
           |  |  | 470 | 			if(flags & ~bob_dom_frame::flagMask)
 | 
        
           |  |  | 471 | 				error(is.tok(), S_Warning, "Unsupported bits set in frame flags - normalizing flags, unsupported values will not be compiled");
 | 
        
           |  |  | 472 |   | 
        
           |  |  | 473 | 			flags&=bob_dom_frame::flagMask;
 | 
        
           |  |  | 474 | 			frame->flags=flags;
 | 
        
           |  |  | 475 |   | 
        
           |  |  | 476 | 			bRes=true;
 | 
        
           |  |  | 477 | 		}
 | 
        
           |  |  | 478 | 	}
 | 
        
           |  |  | 479 |   | 
        
           |  |  | 480 | 	while(bRes){
 | 
        
           |  |  | 481 | 		static const char *pos_context = "frame: position: ";
 | 
        
           |  |  | 482 | 		static const char *rot_context ="frame: rotation: ";
 | 
        
           |  |  | 483 | 		static const char *tpos_context ="frame: target position: ";
 | 
        
           |  |  | 484 | 		static const char *troll_context ="frame: roll angle: ";
 | 
        
           |  |  | 485 | 		static const char *fov_context ="frame: FOV: ";
 | 
        
           |  |  | 486 | 		static const char *color_context ="frame: RGB: ";
 | 
        
           |  |  | 487 | 		static const char *len_context ="frame: length: ";
 | 
        
           |  |  | 488 | 		static const char *idx_context ="frame: index: ";
 | 
        
           |  |  | 489 |   | 
        
           |  |  | 490 | 		if((flags & CUT_F_SAMEPOS)==0){
 | 
        
           |  |  | 491 | 			loadIntValue(is, &(frame->position.x), pos_context);
 | 
        
           |  |  | 492 | 			loadIntValue(is, &(frame->position.y), pos_context);
 | 
        
           |  |  | 493 | 			if((bRes=loadIntValue(is, &(frame->position.z), pos_context))==false) break;
 | 
        
           |  |  | 494 |   | 
        
           |  |  | 495 | 			if(flags & CUT_F_POSTCBINFO) {
 | 
        
           |  |  | 496 | 				frame->pos_tcb_info=new bob_dom_frame::tcb_info();
 | 
        
           |  |  | 497 | 				if((bRes=loadTCBInfo(is, frame->pos_tcb_info))==false) break;
 | 
        
           |  |  | 498 | 			}
 | 
        
           |  |  | 499 | 		}
 | 
        
           |  |  | 500 | 		if((flags & CUT_F_SAMEROT)==0 && (flags & CUT_F_ROT)){
 | 
        
           |  |  | 501 | 			frame->rotation=new bob_dom_frame::angle_axis();
 | 
        
           |  |  | 502 | 			loadDoubleValue(is, &(frame->rotation->angle), rot_context);
 | 
        
           |  |  | 503 | 			loadDoubleValue(is, &(frame->rotation->x), rot_context);
 | 
        
           |  |  | 504 | 			loadDoubleValue(is, &(frame->rotation->y), rot_context);
 | 
        
           |  |  | 505 | 			if((bRes=loadDoubleValue(is, &(frame->rotation->z), rot_context))==false) break;
 | 
        
           |  |  | 506 |   | 
        
           |  |  | 507 | 			if(flags & CUT_F_ROTTCBINFO){
 | 
        
           |  |  | 508 | 				frame->rot_tcb_info=new bob_dom_frame::tcb_info();
 | 
        
           |  |  | 509 | 				if((bRes=loadTCBInfo(is, frame->rot_tcb_info))==false) break;
 | 
        
           |  |  | 510 | 			}
 | 
        
           |  |  | 511 | 		}
 | 
        
           |  |  | 512 | 		if(flags & CUT_F_TARGETPOS){
 | 
        
           |  |  | 513 | 			if((flags & CUT_F_SAMETARGET)==0){
 | 
        
           |  |  | 514 | 				frame->targetPos=new bob_dom_frame::point3d();
 | 
        
           |  |  | 515 | 				loadIntValue(is, &(frame->targetPos->x), tpos_context);
 | 
        
           |  |  | 516 | 				loadIntValue(is, &(frame->targetPos->y), tpos_context);
 | 
        
           |  |  | 517 | 				if((bRes=loadIntValue(is, &(frame->targetPos->z), tpos_context))==false) break;
 | 
        
           |  |  | 518 | 			}
 | 
        
           |  |  | 519 | 			if((flags & CUT_F_SAMEROT)==0){
 | 
        
           |  |  | 520 | 				if((bRes=loadDoubleValue(is, &(frame->rollAngle), troll_context))==false) break;
 | 
        
           |  |  | 521 | 			}
 | 
        
           |  |  | 522 | 			if(flags & CUT_F_TPOSTCBINFO){
 | 
        
           |  |  | 523 | 				frame->tpos_tcb_info=new bob_dom_frame::tcb_info();
 | 
        
           |  |  | 524 | 				if((bRes=loadTCBInfo(is, frame->tpos_tcb_info))==false) break;
 | 
        
           |  |  | 525 | 			}
 | 
        
           |  |  | 526 | 		}
 | 
        
           |  |  | 527 | 		if((flags & CUT_F_SAMEFOV)==0 && flags & CUT_F_FOV){
 | 
        
           |  |  | 528 | 			if((bRes=loadDoubleValue(is, &(frame->fov), fov_context))==false) break;
 | 
        
           |  |  | 529 | 		}
 | 
        
           |  |  | 530 | 		if((flags & CUT_F_SAMECOLOR)==0 && flags & CUT_F_COLOR){
 | 
        
           |  |  | 531 | 			frame->color=new bob_dom_frame::rgb();
 | 
        
           |  |  | 532 | 			loadDoubleValue(is, &(frame->color->r), color_context);
 | 
        
           |  |  | 533 | 			loadDoubleValue(is, &(frame->color->r), color_context);
 | 
        
           |  |  | 534 | 			if((bRes=loadDoubleValue(is, &(frame->color->r), color_context))==false) break;
 | 
        
           |  |  | 535 | 		}
 | 
        
           |  |  | 536 | 		if((bRes=loadIntValue(is, &(frame->length), len_context))==false) break;
 | 
        
           |  |  | 537 | 		if((bRes=loadIntValue(is, &(frame->index), idx_context))==false) break;
 | 
        
           |  |  | 538 |   | 
        
           |  |  | 539 | 		break;
 | 
        
           |  |  | 540 | 	}
 | 
        
           |  |  | 541 | 	if(bRes){
 | 
        
           |  |  | 542 | 		int c=0;
 | 
        
           |  |  | 543 | 		while((t=is.tok()) && t->type!=token::t_closeBracket){
 | 
        
           |  |  | 544 | 			c++;
 | 
        
           |  |  | 545 | 			if(loadValue(is)==false) break;
 | 
        
           |  |  | 546 | 		}
 | 
        
           |  |  | 547 | 		if(t==NULL){
 | 
        
           |  |  | 548 | 			error(is.previous(), S_Error, "Unexpected end of document found while looking for end of frame block '}'");
 | 
        
           |  |  | 549 | 		}
 | 
        
           |  |  | 550 | 		else if(c > 0){
 | 
        
           |  |  | 551 | 			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);
 | 
        
           |  |  | 552 | 		}
 | 
        
           |  |  | 553 | 		++is; // past the end bracket
 | 
        
           |  |  | 554 | 	}
 | 
        
           |  |  | 555 | 	else{
 | 
        
           |  |  | 556 | 		if(is.tok() && is.tok()->type==token::t_closeBracket)
 | 
        
           |  |  | 557 | 			error(is.tok(), S_Error, "Premature end of frame block encountered. Expected %d values (+frame flags)", frame->valueCount() + 2);
 | 
        
           |  |  | 558 | 	}
 | 
        
           |  |  | 559 | 	return bRes;
 | 
        
           |  |  | 560 | }
 | 
        
           |  |  | 561 | #endif // !defined(X2BC_USE_INI_FORMATS)
 | 
        
           |  |  | 562 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 563 | bool bod_cut_parser::loadTCBInfo(token_stream& is, bob_dom_frame::tcb_info *info)
 | 
        
           |  |  | 564 | {
 | 
        
           |  |  | 565 | 	if(!loadDoubleValue(is, &(info->tension), "TCB info (tension): ")) return false;
 | 
        
           |  |  | 566 | 	if(!loadDoubleValue(is, &(info->continuity), "TCB info (continuity): ")) return false;
 | 
        
           |  |  | 567 | 	if(!loadDoubleValue(is, &(info->bias), "TCB info (bias): ")) return false;
 | 
        
           |  |  | 568 | 	if(!loadDoubleValue(is, &(info->easeFrom), "TCB info (ease from): ")) return false;
 | 
        
           |  |  | 569 | 	if(!loadDoubleValue(is, &(info->easeTo), "TCB info (ease to): ")) return false;
 | 
        
           |  |  | 570 | 	return true;
 | 
        
           |  |  | 571 | }
 | 
        
           |  |  | 572 | //---------------------------------------------------------------------------------
 |