예제 #1
0
        /// <summary>
        /// Computes the number of lines of output required to hold the formatted output.
        /// </summary>
        /// <param name="formatter">Format definition.</param>
        /// <param name="dfd">Data format descriptor.</param>
        /// <returns>Line count.</returns>
        public static int ComputeRequiredLineCount(Formatter formatter, PseudoOpNames opNames,
                                                   FormatDescriptor dfd, byte[] data, int offset)
        {
            if (dfd.IsString)
            {
                Debug.Assert(false);        // shouldn't be calling here anymore
                List <string> lines = FormatStringOp(formatter, opNames, dfd, data,
                                                     offset, out string popcode);
                return(lines.Count);
            }

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.Default:
            case FormatDescriptor.Type.NumericLE:
            case FormatDescriptor.Type.NumericBE:
            case FormatDescriptor.Type.Fill:
            case FormatDescriptor.Type.Junk:
                return(1);

            case FormatDescriptor.Type.Dense: {
                // no delimiter, two output bytes per input byte
                int maxLen  = MAX_OPERAND_LEN;
                int textLen = dfd.Length * 2;
                return((textLen + maxLen - 1) / maxLen);
            }

            default:
                Debug.Assert(false);
                return(1);
            }
        }
예제 #2
0
            private static Dictionary <string, string> PropsToDict(PseudoOpNames pon)
            {
                Dictionary <string, string> dict = new Dictionary <string, string>();

                foreach (PropertyInfo prop in pon.GetType().GetProperties())
                {
                    string value = (string)prop.GetValue(pon);
                    if (!string.IsNullOrEmpty(value))
                    {
                        dict[prop.Name] = value;
                    }
                }
                return(dict);
            }
예제 #3
0
            /// <summary>
            /// Merges the non-null, non-empty strings in "other" into this instance.
            /// </summary>
            public void Merge(PseudoOpNames other)
            {
                // Lots of fields, we don't do this often... use reflection.
                Type type = GetType();

                PropertyInfo[] props = type.GetProperties();
                foreach (PropertyInfo pi in props)
                {
                    string str = (string)pi.GetValue(other);
                    if (string.IsNullOrEmpty(str))
                    {
                        continue;
                    }
                    pi.SetValue(this, str);
                }
            }
예제 #4
0
            /// <summary>
            /// Merges the non-null, non-empty strings.
            /// </summary>
            public static PseudoOpNames Merge(PseudoOpNames basePon, PseudoOpNames newPon)
            {
                Dictionary <string, string> baseDict = PropsToDict(basePon);
                Dictionary <string, string> newDict  = PropsToDict(newPon);

                foreach (KeyValuePair <string, string> kvp in newDict)
                {
                    if (string.IsNullOrEmpty(kvp.Value))
                    {
                        continue;
                    }
                    baseDict[kvp.Key] = kvp.Value;
                }

                return(new PseudoOpNames(baseDict));
            }
예제 #5
0
        /// <summary>
        /// Converts a collection of bytes that represent a string into an array of characters,
        /// stripping the high bit.  Framing data, such as leading lengths and trailing nulls,
        /// are not shown.
        /// </summary>
        /// <param name="formatter">Formatter object.</param>
        /// <param name="subType">String sub-type.</param>
        /// <param name="data">File data.</param>
        /// <param name="offset">Offset, within data, of start of string.</param>
        /// <param name="length">Number of bytes to convert.</param>
        /// <param name="popcode">Pseudo-opcode string.</param>
        /// <param name="showHexZeroes">If nonzero, show 1+ zeroes (representing a leading
        ///     length or null-termination) instead of an empty string.</param>
        /// <returns>Array of characters with string data.</returns>
        private static char[] BytesToChars(Formatter formatter, PseudoOpNames opNames,
                                           FormatDescriptor.SubType subType, byte[] data, int offset, int length,
                                           out string popcode, out int showHexZeroes)
        {
            Debug.Assert(length > 0);

            // See also GenMerlin32.OutputString().
            int  strOffset = offset;
            int  strLen    = length;
            bool highAscii = false;
            bool reverse   = false;

            showHexZeroes = 0;

            switch (subType)
            {
            case FormatDescriptor.SubType.None:
                // High or low ASCII, full width specified by formatter.
                highAscii = (data[offset] & 0x80) != 0;
                popcode   = highAscii ? opNames.StrGenericHi : opNames.StrGeneric;
                break;

            case FormatDescriptor.SubType.Dci:
                // High or low ASCII, full width specified by formatter.
                highAscii = (data[offset] & 0x80) != 0;
                popcode   = highAscii ? opNames.StrDciHi : opNames.StrDci;
                break;

            case FormatDescriptor.SubType.Reverse:
                // High or low ASCII, full width specified by formatter.  Show characters
                // in reverse order.
                highAscii = (data[offset + strLen - 1] & 0x80) != 0;
                popcode   = highAscii ? opNames.StrReverseHi : opNames.StrReverse;
                reverse   = true;
                break;

            case FormatDescriptor.SubType.DciReverse:
                // High or low ASCII, full width specified by formatter.  Show characters
                // in reverse order.
                highAscii = (data[offset + strLen - 1] & 0x80) != 0;
                popcode   = highAscii ? opNames.StrDciReverseHi : opNames.StrDciReverse;
                reverse   = true;
                break;

            case FormatDescriptor.SubType.CString:
                // High or low ASCII, with a terminating null.  Don't show the null.  If
                // it's an empty string, just show the null byte as hex.
                highAscii = (data[offset] & 0x80) != 0;
                popcode   = highAscii ? opNames.StrNullTermHi : opNames.StrNullTerm;
                strLen--;
                if (strLen == 0)
                {
                    showHexZeroes = 1;
                }
                break;

            case FormatDescriptor.SubType.L8String:
                // High or low ASCII, with a leading length byte.  Don't show the null.
                // If it's an empty string, just show the length byte as hex.
                strOffset++;
                strLen--;
                if (strLen == 0)
                {
                    showHexZeroes = 1;
                }
                else
                {
                    highAscii = (data[strOffset] & 0x80) != 0;
                }
                popcode = highAscii ? opNames.StrLen8Hi : opNames.StrLen8;
                break;

            case FormatDescriptor.SubType.L16String:
                // High or low ASCII, with a leading length word.  Don't show the null.
                // If it's an empty string, just show the length word as hex.
                Debug.Assert(strLen > 1);
                strOffset += 2;
                strLen    -= 2;
                if (strLen == 0)
                {
                    showHexZeroes = 2;
                }
                else
                {
                    highAscii = (data[strOffset] & 0x80) != 0;
                }
                popcode = highAscii ? opNames.StrLen16Hi : opNames.StrLen16;
                break;

            default:
                Debug.Assert(false);
                popcode = ".!!!";
                break;
            }

            char[] text = new char[strLen];
            if (!reverse)
            {
                for (int i = 0; i < strLen; i++)
                {
                    text[i] = (char)(data[i + strOffset] & 0x7f);
                }
            }
            else
            {
                for (int i = 0; i < strLen; i++)
                {
                    text[i] = (char)(data[strOffset + (strLen - i - 1)] & 0x7f);
                }
            }

            return(text);
        }
예제 #6
0
        /// <summary>
        /// Generates a pseudo-op statement for the specified data operation.
        ///
        /// For most operations, only one output line will be generated.  For larger items,
        /// like long comments, the value may be split into multiple lines.  The sub-index
        /// indicates which line should be formatted.
        /// </summary>
        /// <param name="formatter">Format definition.</param>
        /// <param name="opNames">Table of pseudo-op names.</param>
        /// <param name="symbolTable">Project symbol table.</param>
        /// <param name="labelMap">Symbol label map.  May be null.</param>
        /// <param name="dfd">Data format descriptor.</param>
        /// <param name="data">File data array.</param>
        /// <param name="offset">Start offset.</param>
        /// <param name="subIndex">For multi-line items, which line.</param>
        public static PseudoOut FormatDataOp(Formatter formatter, PseudoOpNames opNames,
                                             SymbolTable symbolTable, Dictionary <string, string> labelMap,
                                             FormatDescriptor dfd, byte[] data, int offset, int subIndex)
        {
            if (dfd == null)
            {
                // should never happen
                //Debug.Assert(false, "Null dfd at offset+" + offset.ToString("x6"));
                PseudoOut failed = new PseudoOut();
                failed.Opcode = failed.Operand = "!FAILED!+" + offset.ToString("x6");
                return(failed);
            }

            int length = dfd.Length;

            Debug.Assert(length > 0);

            // All outputs for a given offset show the same offset and length, even for
            // multi-line items.
            PseudoOut po = new PseudoOut();

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.Default:
                if (length != 1)
                {
                    // This shouldn't happen.
                    Debug.Assert(false);
                    length = 1;
                }
                po.Opcode = opNames.GetDefineData(length);
                int operand = RawData.GetWord(data, offset, length, false);
                po.Operand = formatter.FormatHexValue(operand, length * 2);
                break;

            case FormatDescriptor.Type.NumericLE:
                po.Opcode  = opNames.GetDefineData(length);
                operand    = RawData.GetWord(data, offset, length, false);
                po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd,
                                                  operand, length, FormatNumericOpFlags.None);
                break;

            case FormatDescriptor.Type.NumericBE:
                po.Opcode  = opNames.GetDefineBigData(length);
                operand    = RawData.GetWord(data, offset, length, true);
                po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap, dfd,
                                                  operand, length, FormatNumericOpFlags.None);
                break;

            case FormatDescriptor.Type.Fill:
                po.Opcode  = opNames.Fill;
                po.Operand = length + "," + formatter.FormatHexValue(data[offset], 2);
                break;

            case FormatDescriptor.Type.Dense: {
                int maxPerLine = MAX_OPERAND_LEN / 2;
                offset += subIndex * maxPerLine;
                length -= subIndex * maxPerLine;
                if (length > maxPerLine)
                {
                    length = maxPerLine;
                }
                po.Opcode  = opNames.Dense;
                po.Operand = formatter.FormatDenseHex(data, offset, length);
                //List<PseudoOut> outList = new List<PseudoOut>();
                //GenerateTextLines(text, "", "", po, outList);
                //po = outList[subIndex];
            }
            break;

            case FormatDescriptor.Type.String:
                // It's hard to do strings in single-line pieces because of prefix lengths,
                // terminating nulls, DCI polarity, and reverse-order strings.  We
                // really just want to convert the whole thing to a run of chars
                // and then pull out a chunk.  As an optimization we can handle
                // generic strings (subtype=None) more efficiently, which should solve
                // the problem of massive strings created by auto-analysis.
                if (dfd.FormatSubType == FormatDescriptor.SubType.None)
                {
                    int maxPerLine = MAX_OPERAND_LEN - 2;
                    offset += subIndex * maxPerLine;
                    length -= subIndex * maxPerLine;
                    if (length > maxPerLine)
                    {
                        length = maxPerLine;
                    }
                    char[] ltext = BytesToChars(formatter, opNames, dfd.FormatSubType, data,
                                                offset, length, out string lpopcode, out int unused);
                    po.Opcode  = lpopcode;
                    po.Operand = "\u201c" + new string(ltext) + "\u201d";
                }
                else
                {
                    char[] text = BytesToChars(formatter, opNames, dfd.FormatSubType, data,
                                               offset, length, out string popcode, out int showHexZeroes);

                    if (showHexZeroes == 1)
                    {
                        po.Opcode  = opNames.DefineData1;
                        po.Operand = formatter.FormatHexValue(0, 2);
                    }
                    else if (showHexZeroes == 2)
                    {
                        po.Opcode  = opNames.DefineData2;
                        po.Operand = formatter.FormatHexValue(0, 4);
                    }
                    else
                    {
                        Debug.Assert(showHexZeroes == 0);
                        po.Opcode = popcode;
                        List <PseudoOut> outList = new List <PseudoOut>();
                        GenerateTextLines(text, "\u201c", "\u201d", po, outList);
                        po = outList[subIndex];
                    }
                }
                break;

            default:
                Debug.Assert(false);
                po.Opcode  = ".???";
                po.Operand = "$" + data[offset].ToString("x2");
                break;
            }

            return(po);
        }
예제 #7
0
        /// <summary>
        /// Converts a collection of bytes that represent a string into an array of formatted
        /// string operands.
        /// </summary>
        /// <param name="formatter">Formatter object.</param>
        /// <param name="opNames">Pseudo-opcode name table.</param>
        /// <param name="dfd">Format descriptor.</param>
        /// <param name="data">File data.</param>
        /// <param name="offset">Offset, within data, of start of string.</param>
        /// <param name="popcode">Pseudo-opcode string.</param>
        /// <returns>Array of operand strings.</returns>
        public static List <string> FormatStringOp(Formatter formatter, PseudoOpNames opNames,
                                                   FormatDescriptor dfd, byte[] data, int offset, out string popcode)
        {
            int hiddenLeadingBytes = 0;
            int trailingBytes      = 0;

            StringOpFormatter.ReverseMode revMode = StringOpFormatter.ReverseMode.Forward;
            Formatter.DelimiterSet        delSet  = formatter.Config.mStringDelimiters;
            Formatter.DelimiterDef        delDef;

            CharEncoding.Convert charConv;
            switch (dfd.FormatSubType)
            {
            case FormatDescriptor.SubType.Ascii:
                if (dfd.FormatType == FormatDescriptor.Type.StringDci)
                {
                    charConv = CharEncoding.ConvertLowAndHighAscii;
                }
                else
                {
                    charConv = CharEncoding.ConvertAscii;
                }
                delDef = delSet.Get(CharEncoding.Encoding.Ascii);
                break;

            case FormatDescriptor.SubType.HighAscii:
                if (dfd.FormatType == FormatDescriptor.Type.StringDci)
                {
                    charConv = CharEncoding.ConvertLowAndHighAscii;
                }
                else
                {
                    charConv = CharEncoding.ConvertHighAscii;
                }
                delDef = delSet.Get(CharEncoding.Encoding.HighAscii);
                break;

            case FormatDescriptor.SubType.C64Petscii:
                if (dfd.FormatType == FormatDescriptor.Type.StringDci)
                {
                    charConv = CharEncoding.ConvertLowAndHighC64Petscii;
                }
                else
                {
                    charConv = CharEncoding.ConvertC64Petscii;
                }
                delDef = delSet.Get(CharEncoding.Encoding.C64Petscii);
                break;

            case FormatDescriptor.SubType.C64Screen:
                if (dfd.FormatType == FormatDescriptor.Type.StringDci)
                {
                    charConv = CharEncoding.ConvertLowAndHighC64ScreenCode;
                }
                else
                {
                    charConv = CharEncoding.ConvertC64ScreenCode;
                }
                delDef = delSet.Get(CharEncoding.Encoding.C64ScreenCode);
                break;

            default:
                Debug.Assert(false);
                charConv = CharEncoding.ConvertAscii;
                delDef   = delSet.Get(CharEncoding.Encoding.Ascii);
                break;
            }

            if (delDef == null)
            {
                delDef = Formatter.DOUBLE_QUOTE_DELIM;
            }

            switch (dfd.FormatType)
            {
            case FormatDescriptor.Type.StringGeneric:
                // Generic character data.
                popcode = opNames.StrGeneric;
                break;

            case FormatDescriptor.Type.StringReverse:
                // Character data, full width specified by formatter.  Show characters
                // in reverse order.
                popcode = opNames.StrReverse;
                revMode = StringOpFormatter.ReverseMode.FullReverse;
                break;

            case FormatDescriptor.Type.StringNullTerm:
                // Character data with a terminating null.  Don't show the null byte.
                popcode       = opNames.StrNullTerm;
                trailingBytes = 1;
                //if (strLen == 0) {
                //    showHexZeroes = 1;
                //}
                break;

            case FormatDescriptor.Type.StringL8:
                // Character data with a leading length byte.  Don't show the length.
                hiddenLeadingBytes = 1;
                //if (strLen == 0) {
                //    showHexZeroes = 1;
                //}
                popcode = opNames.StrLen8;
                break;

            case FormatDescriptor.Type.StringL16:
                // Character data with a leading length word.  Don't show the length.
                Debug.Assert(dfd.Length > 1);
                hiddenLeadingBytes = 2;
                //if (strLen == 0) {
                //    showHexZeroes = 2;
                //}
                popcode = opNames.StrLen16;
                break;

            case FormatDescriptor.Type.StringDci:
                // High bit on last byte is flipped.
                popcode = opNames.StrDci;
                break;

            default:
                Debug.Assert(false);
                popcode = ".!!!";
                break;
            }

            StringOpFormatter stropf = new StringOpFormatter(formatter, delDef,
                                                             StringOpFormatter.RawOutputStyle.CommaSep, MAX_OPERAND_LEN, charConv);

            stropf.FeedBytes(data, offset + hiddenLeadingBytes,
                             dfd.Length - hiddenLeadingBytes - trailingBytes, 0, revMode);

            return(stropf.Lines);
        }
예제 #8
0
        /// <summary>
        /// Generates a pseudo-op statement for the specified data operation.
        ///
        /// For most operations, only one output line will be generated.  For larger items,
        /// like dense hex, the value may be split into multiple lines.  The sub-index
        /// indicates which line should be formatted.
        /// </summary>
        /// <param name="formatter">Format definition.</param>
        /// <param name="opNames">Table of pseudo-op names.</param>
        /// <param name="symbolTable">Project symbol table.</param>
        /// <param name="labelMap">Symbol label map.  May be null.</param>
        /// <param name="dfd">Data format descriptor.</param>
        /// <param name="data">File data array.</param>
        /// <param name="offset">Start offset.</param>
        /// <param name="subIndex">For multi-line items, which line.</param>
        public static PseudoOut FormatDataOp(Formatter formatter, PseudoOpNames opNames,
                                             SymbolTable symbolTable, Dictionary <string, string> labelMap,
                                             FormatDescriptor dfd, byte[] data, int offset, int subIndex)
        {
            if (dfd == null)
            {
                // should never happen
                //Debug.Assert(false, "Null dfd at offset+" + offset.ToString("x6"));
                PseudoOut failed = new PseudoOut();
                failed.Opcode = failed.Operand = "!FAILED!+" + offset.ToString("x6");
                return(failed);
            }

            int length = dfd.Length;

            Debug.Assert(length > 0);

            // All outputs for a given offset show the same offset and length, even for
            // multi-line items.
            PseudoOut po = new PseudoOut();

            if (dfd.IsString)
            {
                Debug.Assert(false);        // shouldn't be calling here anymore
                List <string> lines = FormatStringOp(formatter, opNames, dfd, data,
                                                     offset, out string popcode);
                po.Opcode  = popcode;
                po.Operand = lines[subIndex];
            }
            else
            {
                switch (dfd.FormatType)
                {
                case FormatDescriptor.Type.Default:
                    if (length != 1)
                    {
                        // This shouldn't happen.
                        Debug.Assert(false);
                        length = 1;
                    }
                    po.Opcode = opNames.GetDefineData(length);
                    int operand = RawData.GetWord(data, offset, length, false);
                    po.Operand = formatter.FormatHexValue(operand, length * 2);
                    break;

                case FormatDescriptor.Type.NumericLE:
                    po.Opcode  = opNames.GetDefineData(length);
                    operand    = RawData.GetWord(data, offset, length, false);
                    po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap,
                                                      dfd, operand, length, FormatNumericOpFlags.None);
                    break;

                case FormatDescriptor.Type.NumericBE:
                    po.Opcode  = opNames.GetDefineBigData(length);
                    operand    = RawData.GetWord(data, offset, length, true);
                    po.Operand = FormatNumericOperand(formatter, symbolTable, labelMap,
                                                      dfd, operand, length, FormatNumericOpFlags.None);
                    break;

                case FormatDescriptor.Type.Fill:
                    po.Opcode  = opNames.Fill;
                    po.Operand = length + "," + formatter.FormatHexValue(data[offset], 2);
                    break;

                case FormatDescriptor.Type.Junk:
                    if (dfd.FormatSubType != FormatDescriptor.SubType.None)
                    {
                        po.Opcode = opNames.Align;
                        int alignPow = FormatDescriptor.AlignmentToPower(dfd.FormatSubType);
                        po.Operand = formatter.FormatHexValue(1 << alignPow, 2) +
                                     " (" + length.ToString() + " bytes)";
                    }
                    else
                    {
                        po.Opcode  = opNames.Junk;
                        po.Operand = length.ToString();
                    }
                    break;

                case FormatDescriptor.Type.Dense: {
                    int maxPerLine = MAX_OPERAND_LEN / 2;
                    offset += subIndex * maxPerLine;
                    length -= subIndex * maxPerLine;
                    if (length > maxPerLine)
                    {
                        length = maxPerLine;
                    }
                    po.Opcode  = opNames.Dense;
                    po.Operand = formatter.FormatDenseHex(data, offset, length);
                    //List<PseudoOut> outList = new List<PseudoOut>();
                    //GenerateTextLines(text, "", "", po, outList);
                    //po = outList[subIndex];
                }
                break;

                default:
                    Debug.Assert(false);
                    po.Opcode  = ".???";
                    po.Operand = "$" + data[offset].ToString("x2");
                    break;
                }
            }

            return(po);
        }