Subversion Repositories display

Rev

Rev 289 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2007 Steve Ratcliffe
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *
 * Author: Steve Ratcliffe
 * Create date: Dec 16, 2007
 */

package test.display;

import uk.me.parabola.imgfmt.app.ImgFileReader;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

/**
 * Displays data in a manner similar to imgdecode written by John Mechalas.
 *
 * So we have an address on the left, un-decoded bytes in the middle and
 * the decoded text and explanation on the right.
 *
 * @author Steve Ratcliffe
 */

public class Displayer {
        private static final String SEPARATOR = "---------------------------------"
                        + "---------------------------------------------------------------"
                        + "---------------------------------------------------------------"
                        ;
        private static final int TABLE_WIDTH = 80;

        private String title;
        private final List<DisplayItem> items = new ArrayList<DisplayItem>();

        private final ImgFileReader reader;

        // References relative to the section start are much more useful for
        // some purposes.
        private long sectStart;

        public Displayer(ImgFileReader reader) {
                this.reader = reader;
        }

        /**
         * Prints this displayer, and causes all the contained display items to
         * be printed out.
         * @param writer The stream to write to.
         */

        public void print(PrintStream writer) {
                if (writer == null) {
                        items.clear();
                        return;
                }
                printTitle(writer);
                for (DisplayItem item : items) {
                        item.print(writer);
                }
                items.clear();
                writer.flush();
        }

        private void printTitle(PrintStream writer) {
                if (title == null)
                        return;

                int leadin = 9;
                writer.printf("%s ", SEPARATOR.substring(0, leadin));
                writer.print(title);
                writer.printf(" %s", SEPARATOR.substring(0, TABLE_WIDTH - leadin - title.length() - 2));
                writer.println();
        }

        public void setTitle(String title) {
                this.title = title;
        }

        /**
         * Create a display item for the current position.  You can add data and
         * lines of text to it.  If you can its easier to use the convenience
         * routines below.
         *
         * This must be called *before* getting any data from the reader as it
         * records the file position.
         *
         * @return A display item.
         */

        public DisplayItem item() {
                DisplayItem item = new DisplayItem();
                item.setStartPos(reader.position());
                item.setSectStart(sectStart);

                items.add(item);
                return item;
        }

        /**
         * Draw a line across the display.
         */

        public void line() {
                item().addText("------");
        }

        /**
         * Make a gap in the display, nothing will be printed apart from the
         * separators.
         */

        public void gap() {
                item().addText(" ");
        }

        public byte byteValue(String text) {
                DisplayItem item = byteItem();
                int val = item.getValue();
                if (text != null)
                        item.addText(text, val & 0xff);
                return (byte) (val & 0xff);
        }

        public DisplayItem byteItem() {
                DisplayItem item = item();
                item.setBytes(reader.get());
                return item;
        }

        public char charValue(String text) {
                DisplayItem item = charItem();
                int val = item.getValue();
                if (text != null)
                        item.addText(text, (val & 0xffff));
                return (char) val;
        }

        public DisplayItem charItem() {
                DisplayItem item = item();
                item.setBytes(reader.getChar());
                return item;
        }

        public short shortValue(String text) {
                DisplayItem item = item();
                item.setBytes(reader.getChar());
                short val = (short) item.getValue();
                if (text != null)
                        item.addText(text, (short) val);
                return val;
        }

        public int intValue(String text) {
                DisplayItem item = intItem();
                int val = item.getValue();
                if (text != null)
                        item.addText(text, val);
                return val;
        }

        public DisplayItem intItem() {
                DisplayItem item = item();
                item.setBytes(reader.getInt());
                return item;
        }

        public DisplayItem intItem(int n) {
                DisplayItem item = item();
                switch (n) {
                case 1:
                        item.setBytes(reader.get());
                        break;
                case 2:
                        item.setBytes(reader.getChar());
                        break;
                case 3:
                        item.setBytes3(reader.get3());
                        break;
                case 4:
                        item.setBytes(reader.getInt());
                        break;
                }
                return item;
        }

        public int intValue(int n, String text) {
                switch (n) {
                case 1:
                        return byteValue(text) & 0xff;
                case 2:
                        return charValue(text);
                case 3:
                        return int3Value(text);
                case 4:
                        return intValue(text);
                }
                return 0;
        }

        /**
         * Display an unsigned 3 byte quantity.
         */

        public int int3Value(String text) {
                DisplayItem item = int3Item();
                int val = item.getValue();
                if (text != null)
                        item.addText(text, (val & 0xffffff));
                return val;
        }

        public DisplayItem int3Item() {
                DisplayItem item = item();
                item.setBytes3(reader.get3());
                return item;
        }

        public int int3sValue(String text) {
                DisplayItem item = int3Item();
                int val = item.getValue();
                if ((val & 0x800000) != 0)
                        val |= 0xff000000;
                if (text != null)
                        item.addText(text, val);
                return val;
        }

        public DisplayItem rawItem(int n) {
                DisplayItem item = item();
                byte[] buf = reader.get(n);
                item.setBytes(buf);
                return item;
        }

        public byte[] rawValue(int n, String text) {
                if (n <= 0)
                        return null;
                DisplayItem item = item();
                byte[] buf = reader.get(n);
                item.setBytes(buf);
                if (text != null)
                        item.addText(text + " (len: %d, %#x)", n, n);
                return buf;
        }

        public void stringValue(int n, String text) {
                DisplayItem item = item();
                byte[] b = item.setBytes(reader.get(n));
                String val = new String(b);
                if (text != null)
                        item.addText(text, val);
        }

        /**
         * Display a zero terminated string.
         * @param text Description of the value.
         * @return The value as a string, remember that the nul byte is not included
         * so that the string will be one less in length than in the file.
         */

        public String zstringValue(String text) {
                return zstringValue(text, "latin1");
        }
       
        public String zstringValue(String text, String charsetName) {
                DisplayItem item = item();
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                byte b;
                while ((b = reader.get()) != '\0')
                        os.write(b);
                String val = null;
                try {
                        val = os.toString(charsetName);
                } catch (UnsupportedEncodingException e) {
                        val = os.toString();
                }
                os.write('\0');
                item.setBytes(os.toByteArray());
                if (text != null)
                        item.addText(text, val);
                return val;
        }

        public void rawValue(int n) {
                if (n <= 0) {
                        if (n < 0)
                                item().addText("overshoot %d", n);
                        return;
                }

                item().addText("Unknown %d bytes:", n);

                DisplayItem item = item();
                byte[] bytes = item.setBytes(reader.get(n));

                StringBuffer sb = new StringBuffer();
                for (int count = 0; count < bytes.length; count++) {
                        char c = (char) (bytes[count] & 0xff);
                        sb.append(/*Character.isLetterOrDigit(c)*/ c >= 0x20 ? c : '.');

                        if ((count & 0x7) == 7) {
                                item.addText(sb.toString());
                                sb = new StringBuffer();
                        }
                }
                if (sb.length() > 0)
                        item.addText(sb.toString());
        }

        public void setSectStart(long sectStart) {
                this.sectStart = sectStart;
        }
}