//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Web.Mobile;
using System.Web.UI.MobileControls;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Web.Security;
using System.Security.Permissions;
using SR=System.Web.UI.MobileControls.Adapters.SR;
#if COMPILING_FOR_SHIPPED_SOURCE
using Adapters=System.Web.UI.MobileControls.ShippedAdapterSource;
namespace System.Web.UI.MobileControls.ShippedAdapterSource
#else
using Adapters=System.Web.UI.MobileControls.Adapters;
namespace System.Web.UI.MobileControls.Adapters
#endif
{
/*
* WmlMobileTextWriter class.
*
* Copyright (c) 2000 Microsoft Corporation
*/
///
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
[Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
public class WmlMobileTextWriter : MobileTextWriter
{
private TextWriter _realInnerWriter;
private EmptyTextWriter _analyzeWriter;
private bool _analyzeMode = false;
private MobilePage _page;
private Form _currentForm;
private bool[] _usingPostBackType = new bool[] { false, false };
private bool[] _writtenPostBackType = new bool[] { false, false };
private int _numberOfPostBacks;
private bool _postBackCardsEfficient = false;
private IDictionary _formVariables = null;
private IDictionary _controlShortNames = null;
private Stack _layoutStack = new Stack();
private Stack _formatStack = new Stack();
private WmlLayout _currentWrittenLayout = null;
private WmlFormat _currentWrittenFormat = null;
private bool _pendingBreak = false;
private bool _inAnchor = false;
private int _numberOfSoftkeys;
private bool _provideBackButton = false;
private bool _writtenFormVariables = false;
private bool _alwaysScrambleClientIDs = false;
private const String _largeTag = "big";
private const String _smallTag = "small";
private const String _boldTag = "b";
private const String _italicTag = "i";
internal const String _postBackCardPrefix = "__pbc";
private const String _postBackWithVarsCardId = "__pbc1";
private const String _postBackWithoutVarsCardId = "__pbc2";
internal const String _postBackEventTargetVarName = "mcsvt";
internal const String _postBackEventArgumentVarName = "mcsva";
private const String _shortNamePrefix = "mcsv";
private const int _maxShortNameLength = 16;
private static Random _random = new Random();
///
public WmlMobileTextWriter(TextWriter writer, MobileCapabilities device, MobilePage page)
: base(writer, device)
{
_realInnerWriter = writer;
_page = page;
_numberOfSoftkeys = Device.NumberOfSoftkeys;
if (_numberOfSoftkeys > 2)
{
_numberOfSoftkeys = 2;
}
// For phones that don't have a back button, assign a softkey.
if (_numberOfSoftkeys == 2 && !Device.HasBackButton)
{
_numberOfSoftkeys = 1;
_provideBackButton = true;
_alwaysScrambleClientIDs = _provideBackButton &&
!device.CanRenderOneventAndPrevElementsTogether;
}
}
// AnalyzeMode is set to true during first analysis pass of rendering.
///
public bool AnalyzeMode
{
get
{
return _analyzeMode;
}
set
{
_analyzeMode = value;
if (value)
{
_analyzeWriter = new EmptyTextWriter();
InnerWriter = _analyzeWriter;
}
else
{
InnerWriter = _realInnerWriter;
}
}
}
internal bool HasFormVariables
{
get
{
return _writtenFormVariables;
}
}
///
public override void EnterLayout(Style style)
{
if (AnalyzeMode)
{
return;
}
WmlLayout newLayout = new WmlLayout(style, CurrentLayout);
_layoutStack.Push(newLayout);
}
///
public override void ExitLayout(Style style, bool breakAfter)
{
if (!AnalyzeMode)
{
if (breakAfter)
{
PendingBreak = true;
}
_layoutStack.Pop();
}
}
///
public override void EnterFormat(Style style)
{
if (AnalyzeMode)
{
return;
}
WmlFormat newFormat = new WmlFormat(style, CurrentFormat);
_formatStack.Push(newFormat);
}
///
public override void ExitFormat(Style style)
{
if (AnalyzeMode)
{
return;
}
_formatStack.Pop();
}
///
public virtual void BeginForm(Form form)
{
_cachedFormQueryString = null;
_currentForm = form;
_writtenFormVariables = false;
// To keep track of postbacks which submit form variables,
// and postbacks that don't. Used for postback cards
// (see UsePostBackCards)
_usingPostBackType[0] = _usingPostBackType[1] = false;
if (AnalyzeMode)
{
_numberOfPostBacks = 0;
_postBackCardsEfficient = false;
_controlShortNames = null;
}
else
{
PendingBreak = false;
_currentWrittenLayout = null;
_currentWrittenFormat = null;
RenderBeginForm(form);
}
}
///
public virtual void EndForm()
{
if (AnalyzeMode)
{
// Analyze form when done.
PostAnalyzeForm();
}
else
{
RenderEndForm();
}
}
// Single parameter - used for rendering ordinary inline text
// (with encoding but without breaks).
///
public void RenderText(String text)
{
RenderText(text, false, true);
}
// Two parameters - used for rendering encoded text with or without breaks)
///
public void RenderText(String text, bool breakAfter)
{
RenderText(text, breakAfter, true);
}
///
public virtual void RenderText(String text, bool breakAfter, bool encodeText)
{
if (!AnalyzeMode)
{
EnsureLayout();
// Don't use formatting tags inside anchor.
if (!_inAnchor)
{
EnsureFormat();
}
WriteText(text, encodeText);
if (breakAfter)
{
PendingBreak = true;
}
}
}
// Escape '&' in XML if it hasn't been
internal String EscapeAmpersand(String url)
{
const char ampersand = '&';
const String ampEscaped = "amp;";
if (url == null)
{
return null;
}
int ampPos = url.IndexOf(ampersand);
while (ampPos != -1)
{
if (url.Length - ampPos <= ampEscaped.Length ||
url.Substring(ampPos + 1, ampEscaped.Length) != ampEscaped)
{
url = url.Insert(ampPos + 1, ampEscaped);
}
ampPos = url.IndexOf(ampersand, ampPos + ampEscaped.Length + 1);
}
return url;
}
///
public virtual void RenderBeginHyperlink(String targetUrl,
bool encodeUrl,
String softkeyLabel,
bool implicitSoftkeyLabel,
bool mapToSoftkey)
{
if (!AnalyzeMode)
{
EnsureLayout();
EnsureFormat();
WriteBeginTag("a");
Write(" href=\"");
if (encodeUrl)
{
WriteEncodedUrl(targetUrl);
}
else
{
Write(EscapeAmpersand(targetUrl));
}
Write("\"");
if (softkeyLabel != null && softkeyLabel.Length > 0 && !RequiresNoSoftkeyLabels())
{
WriteTextEncodedAttribute("title", softkeyLabel);
}
Write(">");
_inAnchor = true;
}
}
///
public virtual void RenderEndHyperlink(bool breakAfter)
{
if (!AnalyzeMode)
{
WriteEndTag("a");
if (breakAfter)
{
PendingBreak = true;
}
_inAnchor = false;
}
}
///
public virtual void RenderTextBox(String id,
String value,
String format,
String title,
bool password,
int size,
int maxLength,
bool generateRandomID,
bool breakAfter)
{
if (!AnalyzeMode)
{
// Input tags cannot appear inside character formatting tags,
// so close any character formatting.
CloseCharacterFormat();
// Certain devices always render a break before a