RTFStatus RTFReader::Parse(void) { RTFStatus t_status; t_status = kRTFStatusSuccess; while(t_status == kRTFStatusSuccess) { RTFToken t_token; int4 t_value; if (m_input_skip_count > 0) { while(m_input_skip_count > 0) { t_status = ParseToken(t_token, t_value); if (t_status != kRTFStatusSuccess) break; if (t_token == kRTFTokenEnd || t_token == kRTFTokenBeginGroup || t_token == kRTFTokenEndGroup) { m_input_skip_count = 0; break; } if ((t_token & kRTFTokenMask) == kRTFTokenBin) m_input += t_value; m_input_skip_count -= 1; } } if (t_status == kRTFStatusSuccess) t_status = ParseToken(t_token, t_value); if (t_status != kRTFStatusSuccess) break; if (t_token == kRTFTokenEnd) break; if (t_token == kRTFTokenBeginGroup) t_status = m_state . Save(); else if (t_token == kRTFTokenEndGroup) { // Take into account implementation of 'destinations'. bool t_was_list; t_was_list = m_state . GetDestination() == kRTFDestinationLegacyList; bool t_was_list_text; t_was_list_text = m_state . GetDestination() == kRTFDestinationListText; bool t_was_field; t_was_field = m_state . GetDestination() == kRTFDestinationFldInst; // MW-2014-01-08: [[ Bug 11627 ]] If the paragraph attributes have changed then // force a flush so that a new paragraph with said attributes is created. [ This // isn't 100% correct from my reading of the RTF Spec - really paragraph attrs // should be set on the current paragraph as the paragraph is parsed, rather than // before the first text is emitted - however due to the way LiveCode and Word Processors // generate RTF, this at least makes things roundtrip ]. if (m_state . HasParagraphChanged()) Flush(true); t_status = m_state . Restore(); if (t_was_list) { m_state . SetListStyle(m_list_style); m_state . SetListLevel(m_list_level); } else if (t_was_list_text) { if (m_list_skip) m_state . SetListStyle(kMCTextListStyleSkip); } else if (t_was_field && m_state . GetDestination() != kRTFDestinationFldInst) { ProcessField(); } m_attributes_changed = true; } else if ((t_token & kRTFTokenMask) == kRTFTokenBin) { m_input_binary_count = t_value; m_input_state = kRTFInputStateBinary; } else switch(m_state . GetDestination()) { case kRTFDestinationSkip: // If the skipped destination is in fact the 'list' destination then // handle it. We ignore 'pn' destinations if we have a listtable though. if (t_token == kRTFTokenLegacyList && m_lists . Count() == 0) { m_list_style = kMCTextListStyleNone; m_list_level = 0; m_state . SetDestination(kRTFDestinationLegacyList); } else if (t_token == kRTFTokenListTable) m_state . SetDestination(kRTFDestinationListTable); else if (t_token == kRTFTokenListOverrideTable) m_state . SetDestination(kRTFDestinationListOverrideTable); else if (t_token == kRTFTokenFldInst) m_state . SetDestination(kRTFDestinationFldInst); break; case kRTFDestinationNormal: t_status = ParseDocument(t_token, t_value); break; case kRTFDestinationFontTable: t_status = ParseFontTable(t_token, t_value); break; case kRTFDestinationColorTable: t_status = ParseColorTable(t_token, t_value); break; case kRTFDestinationLegacyList: t_status = ParseLegacyList(t_token, t_value); break; case kRTFDestinationLegacyListPrefix: t_status = ParseLegacyListPrefix(t_token, t_value); break; case kRTFDestinationListTable: t_status = ParseListTable(t_token, t_value); break; case kRTFDestinationListTableLevelText: t_status = ParseListTableLevelText(t_token, t_value); break; case kRTFDestinationListOverrideTable: t_status = ParseListOverrideTable(t_token, t_value); break; case kRTFDestinationListText: t_status = ParseListText(t_token, t_value); break; case kRTFDestinationField: break; case kRTFDestinationFldInst: t_status = ParseFldInst(t_token, t_value); break; } } return t_status; }
static int ProcessVariable( void *theEnv, struct lhsParseNode *thePattern, struct lhsParseNode *multifieldHeader, struct lhsParseNode *patternHead, int patternHeadType, struct nandFrame *theNandFrames) { int theType; struct symbolHashNode *theVariable; struct constraintRecord *theConstraints; /*=============================================================*/ /* If a pattern address is being propagated, then treat it as */ /* a single field pattern variable and create a constraint */ /* which indicates that is must be a fact or instance address. */ /* This code will have to be modified for new data types which */ /* can match patterns. */ /*=============================================================*/ if (thePattern->type == PATTERN_CE) { theType = SF_VARIABLE; theVariable = (struct symbolHashNode *) thePattern->value; if (thePattern->derivedConstraints) RemoveConstraint(theEnv,thePattern->constraints); theConstraints = GetConstraintRecord(theEnv); thePattern->constraints = theConstraints; thePattern->constraints->anyAllowed = FALSE; thePattern->constraints->instanceAddressesAllowed = TRUE; thePattern->constraints->factAddressesAllowed = TRUE; thePattern->derivedConstraints = TRUE; } /*===================================================*/ /* Otherwise a pattern variable is being propagated. */ /*===================================================*/ else { theType = thePattern->type; theVariable = (struct symbolHashNode *) thePattern->value; } /*===================================================*/ /* Propagate the variable location to any additional */ /* fields associated with the binding variable. */ /*===================================================*/ if (thePattern->type != PATTERN_CE) { PropagateVariableToNodes(theEnv,thePattern->bottom,theType,theVariable, thePattern,patternHead->beginNandDepth, TRUE,FALSE); if (ProcessField(theEnv,thePattern,multifieldHeader,patternHead,patternHeadType,theNandFrames)) { return(TRUE); } } /*=================================================================*/ /* Propagate the constraints to other fields, slots, and patterns. */ /*=================================================================*/ return(PropagateVariableDriver(theEnv,patternHead,thePattern,multifieldHeader,theType, theVariable,thePattern,TRUE,patternHeadType)); }
void ProcessNextChar(char c) { if (c == '\n') { state = jsBegin; // abandon current parse (if any) and start again return; } switch (state) { case jsBegin: // initial state, expecting '{' if (c == '{') { parser_watcher::StartReceivedMessage(); state = jsExpectId; fieldVal.clear(); fieldId.clear(); arrayDepth = 0; } break; case jsExpectId: // expecting a quoted ID switch (c) { case ' ': // ignore space break; case '"': state = jsId; break; case '}': // empty object, or extra comma at end of field list RemoveLastId(); if (fieldId.size() == 0) { // TODO: should we report this to the monitor as an error? parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); state = jsEndVal; } break; default: state = JsError(); break; } break; case jsId: // expecting an identifier, or in the middle of one switch (c) { case '"': state = jsHadId; break; default: if (c < ' ') { state = JsError(); } else if (c != ':' && c != '^') { if (!fieldId.add(c)) { state = JsError(); } } break; } break; case jsHadId: // had a quoted identifier, expecting ':' switch (c) { case ':': state = jsVal; break; case ' ': break; default: state = JsError(); break; } break; case jsVal: // had ':' or ':[', expecting value switch (c) { case ' ': break; case '"': fieldVal.clear(); state = jsStringVal; break; case '[': if (arrayDepth < MAX_ARRAY_NESTING && fieldId.add('^')) { arrayIndices[arrayDepth] = 0; // start an array ++arrayDepth; } else { state = JsError(); } break; case ']': if (InArray()) { EndArray(); // empty array state = jsEndVal; } else { state = JsError(); // ']' received without a matching '[' first } break; case '-': fieldVal.clear(); // TODO: an report error to the watcher state = (fieldVal.add(c)) ? jsNegIntVal : JsError(); break; case '{': // start of a nested object // TODO: report an error to the watcher state = (fieldId.add(':')) ? jsExpectId : JsError(); break; default: if (c >= '0' && c <= '9') { fieldVal.clear(); fieldVal.add(c); // must succeed because we just cleared fieldVal state = jsIntVal; break; } else { state = JsError(); } } break; case jsStringVal: // just had '"' and expecting a string value switch (c) { case '"': ConvertUnicode(); ProcessField(); state = jsEndVal; break; case '\\': state = jsStringEscape; break; default: if (c < ' ') { state = JsError(); } else { fieldVal.add(c); // ignore any error so that long string parameters // just get truncated } break; } break; case jsStringEscape: // just had backslash in a string if (!fieldVal.full()) { switch (c) { case '"': case '\\': case '/': if (!fieldVal.add(c)) { state = JsError(); } break; case 'n': case 't': if (!fieldVal.add(' ')) // replace newline and tab by space { // parser_watcher::ProcessError(); state = JsError(); } break; case 'b': case 'f': case 'r': default: break; } } state = jsStringVal; break; case jsNegIntVal: // had '-' so expecting a integer value // TODO: report an error to the watcher state = (c >= '0' && c <= '9' && fieldVal.add(c)) ? jsIntVal : JsError(); break; case jsIntVal: // receiving an integer value switch (c) { case '.': state = (fieldVal.add(c)) ? jsFracVal : JsError(); break; case ',': ProcessField(); if (InArray()) { ++arrayIndices[arrayDepth - 1]; fieldVal.clear(); state = jsVal; } else { RemoveLastId(); state = jsExpectId; } break; case ']': if (InArray()) { ProcessField(); ++arrayIndices[arrayDepth - 1]; EndArray(); state = jsEndVal; } else { state = JsError(); } break; case '}': if (InArray()) { state = JsError(); } else { ProcessField(); RemoveLastId(); if (fieldId.size() == 0) { parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); state = jsEndVal; } } break; default: if (!(c >= '0' && c <= '9' && fieldVal.add(c))) { state = JsError(); } break; } break; case jsFracVal: // receiving a fractional value switch (c) { case ',': ProcessField(); if (InArray()) { ++arrayIndices[arrayDepth - 1]; state = jsVal; } else { RemoveLastId(); state = jsExpectId; } break; case ']': if (InArray()) { ProcessField(); ++arrayIndices[arrayDepth - 1]; EndArray(); state = jsEndVal; } else { state = JsError(); } break; case '}': if (InArray()) { state = JsError(); } else { ProcessField(); RemoveLastId(); if (fieldId.size() == 0) { parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); state = jsEndVal; } } break; default: if (!(c >= '0' && c <= '9' && fieldVal.add(c))) { state = JsError(); } break; } break; case jsEndVal: // had the end of a string or array value, expecting comma // or ] or } switch (c) { case ',': if (InArray()) { ++arrayIndices[arrayDepth - 1]; fieldVal.clear(); state = jsVal; } else { RemoveLastId(); state = jsExpectId; } break; case ']': if (InArray()) { ++arrayIndices[arrayDepth - 1]; EndArray(); } else { state = JsError(); } break; case '}': if (InArray()) { state = JsError(); } else { RemoveLastId(); if (fieldId.size() == 0) { parser_watcher::EndReceivedMessage(); state = jsBegin; } else { RemoveLastIdChar(); // state = jsEndVal; // not needed, state == jsEndVal already } } break; default: break; } break; case jsError: // Ignore all characters. State will be reset to jsBegin at the start of // this function when we receive a newline. break; } }
static int GetVariables( void *theEnv, struct lhsParseNode *thePattern, int patternHeadType, struct nandFrame *theNandFrames) { struct lhsParseNode *patternHead = thePattern; struct lhsParseNode *multifieldHeader = NULL; /*======================================================*/ /* Loop through all the fields/slots found in a pattern */ /* looking for binding instances of variables. */ /*======================================================*/ while (thePattern != NULL) { /*================================================*/ /* A multifield slot contains a sublist of fields */ /* that must be traversed and checked. */ /*================================================*/ if (thePattern->multifieldSlot) { multifieldHeader = thePattern; thePattern = thePattern->bottom; } /*==================================================*/ /* Propagate the binding occurences of single field */ /* variables, multifield variables, and fact */ /* addresses to other occurences of the variable. */ /* If an error is encountered, return TRUE. */ /*==================================================*/ if (thePattern != NULL) { if ((thePattern->type == SF_VARIABLE) || (thePattern->type == MF_VARIABLE) || ((thePattern->type == PATTERN_CE) && (thePattern->value != NULL))) { if (ProcessVariable(theEnv,thePattern,multifieldHeader,patternHead,patternHeadType,theNandFrames)) { return(TRUE); } } else { if (ProcessField(theEnv,thePattern,multifieldHeader,patternHead,patternHeadType,theNandFrames)) { return(TRUE); } } } /*===============================================*/ /* Move on to the next field/slot in the pattern */ /* or to the next field in a multifield slot. */ /*===============================================*/ if (thePattern == NULL) { thePattern = multifieldHeader; } else if ((thePattern->right == NULL) && (multifieldHeader != NULL)) { thePattern = multifieldHeader; multifieldHeader = NULL; } thePattern = thePattern->right; } /*===============================*/ /* Return FALSE to indicate that */ /* no errors were detected. */ /*===============================*/ return(FALSE); }