Example #1
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="formatter">Reference to text formatter.</param>
        /// <param name="delimiterDef">String delimiter values.</param>
        /// <param name="byteStyle">How to format raw byte data.</param>
        /// <param name="charConv">Character conversion delegate.</param>
        public StringOpFormatter(Formatter formatter, Formatter.DelimiterDef delimiterDef,
                                 RawOutputStyle byteStyle, CharEncoding.Convert charConv)
        {
            mRawStyle      = byteStyle;
            mMaxOperandLen = formatter.OperandWrapLen;
            CharConv       = charConv;

            mDelimiterDef = delimiterDef;
            mBuffer       = new char[mMaxOperandLen];
            mHexChars     = formatter.HexDigits;
            Lines         = new List <string>();

            // suffix not used, so we don't expect it to be set to something
            Debug.Assert(string.IsNullOrEmpty(mDelimiterDef.Suffix));

            Reset();
        }
Example #2
0
        /// <summary>
        /// Constructor.  Initializes various fields based on the configuration.  We want to
        /// do as much work as possible here.
        /// </summary>
        public Formatter(FormatConfig config)
        {
            mFormatConfig = config;     // copy struct
            if (mFormatConfig.mEndOfLineCommentDelimiter == null)
            {
                mFormatConfig.mEndOfLineCommentDelimiter = string.Empty;
            }
            if (mFormatConfig.mFullLineCommentDelimiterBase == null)
            {
                mFormatConfig.mFullLineCommentDelimiterBase = string.Empty;
            }
            if (mFormatConfig.mBoxLineCommentDelimiter == null)
            {
                mFormatConfig.mBoxLineCommentDelimiter = string.Empty;
            }

            if (string.IsNullOrEmpty(mFormatConfig.mNonUniqueLabelPrefix))
            {
                mFormatConfig.mNonUniqueLabelPrefix = "@";
            }

            if (mFormatConfig.mAddSpaceLongComment)
            {
                mFullLineCommentDelimiterPlus = mFormatConfig.mFullLineCommentDelimiterBase + " ";
            }
            else
            {
                mFullLineCommentDelimiterPlus = mFormatConfig.mFullLineCommentDelimiterBase;
            }

            // Prep the static parts of the hex dump buffer.
            mHexDumpBuffer = new char[73];
            for (int i = 0; i < mHexDumpBuffer.Length; i++)
            {
                mHexDumpBuffer[i] = ' ';
            }
            mHexDumpBuffer[6] = ':';

            // Resolve boolean flags to character or string values.
            if (mFormatConfig.mUpperHexDigits)
            {
                mHexFmtChar = 'X';
            }
            else
            {
                mHexFmtChar = 'x';
            }
            if (mFormatConfig.mSuppressHexNotation)
            {
                mHexPrefix = "";
            }
            else
            {
                mHexPrefix = "$";
            }
            if (mFormatConfig.mSuppressImpliedAcc)
            {
                mAccChar = "";
            }
            else if (mFormatConfig.mUpperOperandA)
            {
                mAccChar = "A";
            }
            else
            {
                mAccChar = "a";
            }
            if (mFormatConfig.mUpperOperandXY)
            {
                mXregChar = 'X';
                mYregChar = 'Y';
            }
            else
            {
                mXregChar = 'x';
                mYregChar = 'y';
            }
            if (mFormatConfig.mUpperOperandS)
            {
                mSregChar = 'S';
            }
            else
            {
                mSregChar = 's';
            }

            // process the delimiter patterns
            DelimiterSet chrDelim = mFormatConfig.mCharDelimiters;

            if (chrDelim == null)
            {
                Debug.WriteLine("NOTE: char delimiters not set");
                chrDelim = DelimiterSet.GetDefaultCharDelimiters();
            }

            switch (mFormatConfig.mHexDumpCharConvMode)
            {
            case FormatConfig.CharConvMode.Ascii:
                mHexDumpCharConv = CharEncoding.ConvertAscii;
                break;

            case FormatConfig.CharConvMode.LowHighAscii:
                mHexDumpCharConv = CharEncoding.ConvertLowAndHighAscii;
                break;

            case FormatConfig.CharConvMode.C64Petscii:
                mHexDumpCharConv = CharEncoding.ConvertC64Petscii;
                break;

            case FormatConfig.CharConvMode.C64ScreenCode:
                mHexDumpCharConv = CharEncoding.ConvertC64ScreenCode;
                break;

            default:
                // most some things don't configure the hex dump; this is fine
                mHexDumpCharConv = CharEncoding.ConvertLowAndHighAscii;
                break;
            }
        }
Example #3
0
        private void OutputString(int offset, string labelStr, string commentStr)
        {
            // Generic strings whose encoding matches the configured text encoding are output
            // with a simple .text directive.
            //
            // CString and L8String have directives (.null, .ptext), but we can only use
            // them if the string fits on one line and doesn't include delimiters.
            //
            // We might be able to define a macro for Reverse.
            //
            // We don't currently switch character encodings in the middle of a file.  We could
            // do so to flip between PETSCII, screen codes, low ASCII, and high ASCII, but it
            // adds a lot of noise and it's unclear that this is generally useful.

            Anattrib         attr = Project.GetAnattrib(offset);
            FormatDescriptor dfd  = attr.DataDescriptor;

            Debug.Assert(dfd != null);
            Debug.Assert(dfd.IsString);
            Debug.Assert(dfd.Length > 0);

            CharEncoding.Convert charConv = null;
            CharEncoding.Convert dciConv  = null;
            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.Ascii:
                charConv = CharEncoding.ConvertAscii;
                dciConv  = CharEncoding.ConvertLowAndHighAscii;
                break;

            case FormatDescriptor.SubType.HighAscii:
                charConv = CharEncoding.ConvertHighAscii;
                dciConv  = CharEncoding.ConvertLowAndHighAscii;
                break;

            case FormatDescriptor.SubType.C64Petscii:
                charConv = CharEncoding.ConvertC64Petscii;
                dciConv  = CharEncoding.ConvertLowAndHighC64Petscii;
                break;

            case FormatDescriptor.SubType.C64Screen:
                charConv = CharEncoding.ConvertC64ScreenCode;
                dciConv  = CharEncoding.ConvertLowAndHighC64ScreenCode;
                break;

            default:
                break;
            }
            if (charConv == null)
            {
                OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                return;
            }

            // Issue a .enc, if needed.
            UpdateCharacterEncoding(dfd);

            Formatter formatter = SourceFormatter;

            byte[] data = Project.FileData;
            int    hiddenLeadingBytes = 0;
            int    shownLeadingBytes  = 0;
            int    trailingBytes      = 0;
            string opcodeStr;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
                opcodeStr = sDataOpNames.StrGeneric;
                break;

            case FormatDescriptor.Type.StringNullTerm:
                opcodeStr     = sDataOpNames.StrNullTerm;
                trailingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL8:
                opcodeStr          = sDataOpNames.StrLen8;
                hiddenLeadingBytes = 1;
                break;

            case FormatDescriptor.Type.StringL16:
                opcodeStr         = sDataOpNames.StrGeneric;
                shownLeadingBytes = 2;
                break;

            case FormatDescriptor.Type.StringDci:
                opcodeStr = sDataOpNames.StrDci;
                if ((Project.FileData[offset] & 0x80) != 0)
                {
                    // ".shift" directive only works for strings where the low bit starts
                    // clear and ends high.
                    OutputNoJoy(offset, dfd.Length, labelStr, commentStr);
                    return;
                }
                break;

            default:
                Debug.Assert(false);
                return;
            }

            StringOpFormatter stropf = new StringOpFormatter(SourceFormatter,
                                                             Formatter.DOUBLE_QUOTE_DELIM, StringOpFormatter.RawOutputStyle.CommaSep,
                                                             MAX_OPERAND_LEN, charConv);

            if (dfd.FormatType == FormatDescriptor.Type.StringDci)
            {
                // DCI is awkward because the character encoding flips on the last byte.  Rather
                // than clutter up StringOpFormatter for this rare item, we just accept low/high
                // throughout.
                stropf.CharConv = dciConv;
            }

            // Feed bytes in, skipping over hidden bytes (leading L8, trailing null).
            stropf.FeedBytes(data, offset + hiddenLeadingBytes,
                             dfd.Length - hiddenLeadingBytes - trailingBytes, shownLeadingBytes,
                             StringOpFormatter.ReverseMode.Forward);
            Debug.Assert(stropf.Lines.Count > 0);

            // See if we need to do this over.
            bool redo = false;

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
            case FormatDescriptor.Type.StringReverse:
            case FormatDescriptor.Type.StringL16:
                // All good the first time.
                break;

            case FormatDescriptor.Type.StringNullTerm:
            case FormatDescriptor.Type.StringL8:
            case FormatDescriptor.Type.StringDci:
                if (stropf.Lines.Count != 1)
                {
                    // Must be single-line.
                    opcodeStr       = sDataOpNames.StrGeneric;
                    stropf.CharConv = charConv;     // undo DCI hack
                    redo            = true;
                }
                break;

            default:
                Debug.Assert(false);
                return;
            }

            if (redo)
            {
                //Debug.WriteLine("REDO off=+" + offset.ToString("x6") + ": " + dfd.FormatType);

                // This time, instead of skipping over leading length bytes, we include them
                // explicitly.
                stropf.Reset();
                stropf.FeedBytes(data, offset, dfd.Length, hiddenLeadingBytes,
                                 StringOpFormatter.ReverseMode.Forward);
            }

            opcodeStr = formatter.FormatPseudoOp(opcodeStr);

            foreach (string str in stropf.Lines)
            {
                OutputLine(labelStr, opcodeStr, str, commentStr);
                labelStr = commentStr = string.Empty;       // only show on first
            }
        }