Пример #1
0
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;
}
Пример #2
0
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));
  }
Пример #3
0
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;
  }
}
Пример #4
0
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);
  }