nsresult
nsLoggingSink::OpenNode(const char* aKind, const nsIParserNode& aNode) {
	WriteTabs(mOutput,++mLevel);

  PR_fprintf(mOutput,"<open container=");

  nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
  if ((nodeType >= eHTMLTag_unknown) &&
      (nodeType <= nsHTMLTag(NS_HTML_TAG_MAX))) {
    const PRUnichar* tag = nsHTMLTags::GetStringValue(nodeType);
    PR_fprintf(mOutput, "\"%s\"", NS_ConvertUTF16toUTF8(tag).get());
  }
  else {
    char* text = nsnull;
    GetNewCString(aNode.GetText(), &text);
    if(text) {
      PR_fprintf(mOutput, "\"%s\"", text);
      nsMemory::Free(text);
    }
  }

  if (WillWriteAttributes(aNode)) {
    PR_fprintf(mOutput, ">\n");
    WriteAttributes(aNode);
    PR_fprintf(mOutput, "</open>\n");
  }
  else {
    PR_fprintf(mOutput, ">\n");
  }

  return NS_OK;
}
nsresult
nsLoggingSink::LeafNode(const nsIParserNode& aNode)
{
  WriteTabs(mOutput,1+mLevel);
  nsHTMLTag nodeType  = nsHTMLTag(aNode.GetNodeType());

  if ((nodeType >= eHTMLTag_unknown) &&
      (nodeType <= nsHTMLTag(NS_HTML_TAG_MAX))) {
    const PRUnichar* tag = nsHTMLTags::GetStringValue(nodeType);

    if(tag)
      PR_fprintf(mOutput, "<leaf tag=\"%s\"", NS_ConvertUTF16toUTF8(tag).get());
    else
      PR_fprintf(mOutput, "<leaf tag=\"???\"");

    if (WillWriteAttributes(aNode)) {
      PR_fprintf(mOutput, ">\n");
      WriteAttributes(aNode);
      PR_fprintf(mOutput, "</leaf>\n");
    }
    else {
      PR_fprintf(mOutput, "/>\n");
    }
  }
  else {
    PRInt32 pos;
    nsAutoString tmp;
    char* str = nsnull;
    switch (nodeType) {
    case eHTMLTag_whitespace:
    case eHTMLTag_text:
      GetNewCString(aNode.GetText(), &str);
      if(str) {
        PR_fprintf(mOutput, "<text value=\"%s\"/>\n", str);
        nsMemory::Free(str);
      }
      break;

    case eHTMLTag_newline:
      PR_fprintf(mOutput, "<newline/>\n");
      break;

    case eHTMLTag_entity:
      tmp.Append(aNode.GetText());
      tmp.Cut(0, 1);
      pos = tmp.Length() - 1;
      if (pos >= 0) {
        tmp.Cut(pos, 1);
      }
      PR_fprintf(mOutput, "<entity value=\"%s\"/>\n", NS_LossyConvertUTF16toASCII(tmp).get());
      break;

    default:
      NS_NOTREACHED("unsupported leaf node type");
    }//switch
  }
  return NS_OK;
}
NS_IMETHODIMP 
mozSanitizingHTMLSerializer::AddLeaf(const nsIParserNode& aNode)
{
  eHTMLTags type = (eHTMLTags)aNode.GetNodeType();
  const nsAString& text = aNode.GetText();

  mParserNode = const_cast<nsIParserNode*>(&aNode);
  return DoAddLeaf(type, text);
}
NS_IMETHODIMP
mozSanitizingHTMLSerializer::OpenContainer(const nsIParserNode& aNode)
{
  PRInt32 type = aNode.GetNodeType();

  mParserNode = const_cast<nsIParserNode *>(&aNode);
  return DoOpenContainer(type);
}
nsresult
nsLoggingSink::WriteAttributes(const nsIParserNode& aNode) {

  WriteTabs(mOutput,1+mLevel);
  nsAutoString tmp;
  PRInt32 ac = aNode.GetAttributeCount();
  for (PRInt32 i = 0; i < ac; ++i) {
    char* key=nsnull;
    char* value=nsnull;
    const nsAString& k = aNode.GetKeyAt(i);
    const nsAString& v = aNode.GetValueAt(i);

    GetNewCString(k, &key);
    if(key) {
      PR_fprintf(mOutput, " <attr key=\"%s\" value=\"", key);
      nsMemory::Free(key);
    }
 
    tmp.Truncate();
    tmp.Append(v);
    if(!tmp.IsEmpty()) {
      PRUnichar first = tmp.First();
      if ((first == '"') || (first == '\'')) {
        if (tmp.Last() == first) {
          tmp.Cut(0, 1);
          PRInt32 pos = tmp.Length() - 1;
          if (pos >= 0) {
            tmp.Cut(pos, 1);
          }
        } else {
          // Mismatched quotes - leave them in
        }
      }
      GetNewCString(tmp, &value);

      if(value) {
        PR_fprintf(mOutput, "%s\"/>\n", value);
        WriteTabs(mOutput,1+mLevel);
        nsMemory::Free(value);
      }
    }
  }

  WriteTabs(mOutput,1+mLevel);
  return NS_OK;
}
PRBool
nsLoggingSink::WillWriteAttributes(const nsIParserNode& aNode)
{
  PRInt32 ac = aNode.GetAttributeCount();
  if (0 != ac) {
    return PR_TRUE;
  }
  return PR_FALSE;
}
nsresult FBMLContentSink::AddComment(const nsIParserNode& aNode) {
  PRInt32 tagId = aNode.GetNodeType();

#ifdef VERBOSE_LOGGING
  printf("AddComment: %d\n", tagId);
  string text;
  nsString stext(aNode.GetText());
  UTF16ToStdString(text, stext);
  printf("\tComment Text: [%s]\n", text.c_str());
#endif

  if (mPreserveComment) {
    OpenContainer(aNode);
    PRInt32 lineNo = aNode.GetSourceLineNumber();
    fbml_node *node = fbml_node_add_child(mCurrent, tagId, GetFlag(tagId), lineNo);
    string text;
    nsString stext(aNode.GetText());
    UTF16ToStdString(text, stext);
    node->text = strdup(text.c_str());

    CloseContainer((nsHTMLTag)tagId);
  }
  return NS_OK;
}
/**
 *  This gets called by the parser when you want to add
 *  a PI node to the current container in the content
 *  model.
 *  
 *  @updated gess 3/25/98
 *  @param   
 *  @return  
 */
NS_IMETHODIMP
nsLoggingSink::AddProcessingInstruction(const nsIParserNode& aNode){

#ifdef VERBOSE_DEBUG
  DebugDump("<",aNode.GetText(),(mNodeStackPos)*2);
#endif

  nsresult theResult=NS_OK;

  //then proxy the call to the real sink if you have one.
  if(mSink) {
    theResult=mSink->AddProcessingInstruction(aNode);
  }
  
  return theResult;
}
nsresult FBMLContentSink::OpenContainer(const nsIParserNode& aNode) {
  PRInt32 tagId = aNode.GetNodeType();
  bool attrSpecial = false;
  contexts *back_contexts;
  PRInt32 attrId;
#ifdef VERBOSE_LOGGING
  printf("OpenContainer: %d [%s]\n", tagId,
         GetTagName((nsHTMLTag)tagId).c_str());
#endif
  if (mRuleStack.empty()) {
    back_contexts = NULL;
  } else {
    back_contexts = mRuleStack.back();
  }
  if (tagId == eHTMLTag_userdefined) {
    string text;
    nsString stext(aNode.GetText());
    UTF16ToStdString(text, stext);

    PRInt32 lineNo = aNode.GetSourceLineNumber();
    char errorMsg[512];
    snprintf(errorMsg, sizeof(errorMsg),
             "FBML Error (line %d): unknown tag \"%s\"\n",
             (int)lineNo, text.c_str());
    mError += errorMsg;
  } else if (!mSkipSchemaChecking && mCurrent && back_contexts) {
    // check illegal children

    vector<vector<char> > &rules = back_contexts->tag_rules;
    if (tagId >= 0 && tagId < rules.size()) {
      for (fbml_node *p = mCurrent; p; p = p->parent) {
        unsigned short parentTagId = p->eHTMLTag;
        if (parentTagId >= rules.size() || rules[tagId][parentTagId]) {
          PRInt32 lineNo = aNode.GetSourceLineNumber();
          char errorMsg[512];
          snprintf(errorMsg, sizeof(errorMsg),
                   "FBML Error (line %d): illegal tag \"%s\" under \"%s\"\n",
                   (int)lineNo,
                   GetTagName((nsHTMLTag)tagId).c_str(),
                   GetTagName((nsHTMLTag)parentTagId).c_str());
          mError += errorMsg;
          tagId = eHTMLTag_userdefined; // nuke it
        }
      }
    }
  }

  PRInt32 lineNo = aNode.GetSourceLineNumber();
  fbml_node *node = fbml_node_add_child(mCurrent, tagId, GetFlag(tagId), lineNo);
  if (node) {
    int count = aNode.GetAttributeCount();
    for (int i = 0; i < count; i++) {
      string n; nsString sn(aNode.GetKeyAt(i));   UTF16ToStdString(n, sn);
      string v; nsString sv(aNode.GetValueAt(i)); UTF16ToUTF8String(v, sv);
      attrId = nsHTMLAttrs::LookupAttr(sn);
      char attrFlag = GetAttrFlag(attrId);
      // If we are in internal page skip all these checks
      if (mSkipSchemaChecking) {
        fbml_node_add_attribute(node, (char*)n.c_str(), (char*)v.c_str(), attrFlag, 1);
        continue;
      }


      bool fail = false;
      for (char *p = (char*)n.c_str(); *p; p++) {
        if (*p >= 'A' && *p <= 'Z') *p |= 0x20;
        // make sure attrs are well formed
        if (*p != ':' && *p !='_' && *p != '-' && (*p<'a' || *p>'z') && (*p<'0' || *p>'9') ) {
          fail = true;
          break;
        }

      }
      if (fail) {
        PRInt32 lineNo = aNode.GetSourceLineNumber();
        char errorMsg[512];
        snprintf(errorMsg, sizeof(errorMsg),
                 "FBML Error (line %d): illegal attr \"%s\" in tag \"%s\". Attribute names can only contain alphanumeric characters, underscores, and hyphens.",
                 (int)lineNo,
                 n.c_str(),
                 GetTagName((nsHTMLTag)tagId).c_str()
                 );
        mError += errorMsg;

      }
      // check schema
      else if (back_contexts && attrId >= 0 &&
          attrId < back_contexts->attr_rules.size() &&
          back_contexts->attr_rules[attrId]) {
        PRInt32 lineNo = aNode.GetSourceLineNumber();
        char errorMsg[512];
        snprintf(errorMsg, sizeof(errorMsg),
                 "FBML Error (line %d): illegal attr \"%s\" in tag \"%s\" under \"%s\"\n",
                 (int)lineNo,
                 n.c_str(),
                 GetTagName((nsHTMLTag)tagId).c_str(),
                 back_contexts->tag_name.c_str());
        mError += errorMsg;
      }  else if (mCSSSanitizer && (attrFlag & FB_FLAG_ATTR_STYLE)) {
        char *sanitized_css = NULL;
        char *error = NULL;
        int ret = fbml_sanitize_css((char*)v.c_str(), 1, lineNo,
                                    mCSSSanitizer, &sanitized_css, &error);
        if (sanitized_css) {
          fbml_node_add_attribute(node, (char*)n.c_str(), sanitized_css, attrFlag, 0);
        }
        if (error) {
          mError += error;
          free(error);
        }
      } else if (mJSSanitizer && (attrFlag & FB_FLAG_ATTR_SCRIPT)) {
        char *sanitized_js = NULL;
        char *error = NULL;
        int ret = fbml_sanitize_js((char*)v.c_str(), v.length(), 1, lineNo,
                                   mJSSanitizer, &sanitized_js, &error);
        if (sanitized_js) {

          if (mJSSanitizer->pfunc_eh_translator) {
            char *translated = mJSSanitizer->pfunc_eh_translator
              (sanitized_js, mJSSanitizer->eh_translate_data);
            free(sanitized_js);
            sanitized_js = translated;
          }


          fbml_node_add_attribute(node, (char*)n.c_str(), sanitized_js, attrFlag, 0);
        }
        if (error) {
          mError += error;
          free(error);
        }
      } else if (mRewriter && mRewriter->pfunc_rewriter && (attrFlag & FB_FLAG_ATTR_REWRITE)){
        char *rewritten_attr =
          mRewriter->pfunc_rewriter((char *)GetTagName((nsHTMLTag)tagId).c_str(),
                                    (char *)n.c_str(),
                                    (char *)v.c_str(), mRewriter->rewrite_data);
        fbml_node_add_attribute(node, (char*)n.c_str(), rewritten_attr, attrFlag, 0);

      } else {
        if (attrFlag & FB_FLAG_ATTR_SPECIAL) {
          attrSpecial = true;
        }
        fbml_node_add_attribute(node, (char*)n.c_str(), (char*)v.c_str(), attrFlag, 1);
      }
    }

    if (attrSpecial) {
      fbml_node_add_flags(node, FB_FLAG_HAS_SPECIAL_ATTR);
    }
    mCurrent = node;

    if (!mSkipSchemaChecking && tagId >= 0 && tagId < m_context_rules.size()) {
      contexts *rule = &m_context_rules[tagId];
      if (rule &&
          (!rule->tag_rules.empty() || !rule->attr_rules.empty())) {
        mRuleStack.push_back(rule);
      } else if (mRuleStack.empty()) {
        mRuleStack.push_back(NULL);
      } else {
        mRuleStack.push_back(mRuleStack.back());
      }
    } else {
      mRuleStack.push_back(NULL);
    }
  }
  return NS_OK;
}
nsresult FBMLContentSink::AddLeaf(const nsIParserNode& aNode) {
  PRInt32 tagId = aNode.GetNodeType();

#ifdef VERBOSE_LOGGING
  printf("AddLeaf: %d [%s] Attribute Count: [%d]\n", tagId,
         GetTagName((nsHTMLTag)tagId).c_str(), aNode.GetAttributeCount());
  string text;
  nsString stext(aNode.GetText());
  UTF16ToStdString(text, stext);
  printf("\tLeaf Text: [%s]\n", text.c_str());
#endif
  if (tagId == eHTMLTag_title || tagId == eHTMLTag_script ||
      (GetFlag(tagId) & FB_FLAG_STYLE)) {
    nsCOMPtr<nsIDTD> dtd;
    mParser->GetDTD(getter_AddRefs(dtd));
    nsAutoString script;
    PRInt32 lineNo = 0;
    dtd->CollectSkippedContent(tagId, script, lineNo);
    string text;
    UTF16ToStdString(text, script);
#ifdef VERBOSE_LOGGING
    printf("\tCollected Content:: [%s]\n", text.c_str());
#endif

    OpenContainer(aNode);
    fbml_node *node = fbml_node_add_child(mCurrent, tagId, GetFlag(tagId), lineNo);

    if (mCSSSanitizer && (GetFlag(tagId) & FB_FLAG_STYLE)) {
      char *sanitized_css = NULL;
      char *error = NULL;
      int ret = fbml_sanitize_css((char*)text.c_str(), 0, lineNo,
                                  mCSSSanitizer, &sanitized_css, &error);
      if (sanitized_css) {
        node->text = sanitized_css;
      }
      if (error) {
        mError += error;
        free(error);
      }
    } else if (mJSSanitizer && tagId == eHTMLTag_script) {
      char *sanitized_js = NULL;
      char *error = NULL;
      int ret = fbml_sanitize_js((char*)text.c_str(), text.length(), 0,
                                 lineNo, mJSSanitizer, &sanitized_js,
                                 &error);
      if (sanitized_js) {
        node->text = sanitized_js;
      }
      if (error) {
        mError += error;
        free(error);
      }
    } else {
      node->text = strdup(text.c_str());
    }

    CloseContainer((nsHTMLTag)tagId);
    return NS_OK;
  }


  switch (aNode.GetTokenType()) {
  case eToken_start:
    OpenContainer(aNode);
    CloseContainer((nsHTMLTag)tagId);
    break;
  case eToken_text:
  case eToken_whitespace:
  case eToken_newline:
    {
      PRInt32 lineNo = aNode.GetSourceLineNumber();
      fbml_node *node = fbml_node_add_child(mCurrent, tagId, GetFlag(tagId), lineNo);
      string text;
      nsString stext(aNode.GetText());
      UTF16ToStdString(text, stext);
      node->text = strdup(text.c_str());
    }
    break;
  }
  return NS_OK;
}