SforzandoCF

sbprinter

Oct 16th, 2025 (edited)
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 20.85 KB | None | 0 0
  1. import java.io.DataInput;
  2. import java.io.DataInputStream;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.math.BigInteger;
  6. import java.nio.ByteBuffer;
  7. import java.util.HexFormat;
  8. import java.util.Map;
  9.  
  10. public class SBPrinter {
  11.     public static void main (String[] args) {
  12.         if (args.length < 1)
  13.             System.out.println("Usage: java sbprinter [path]");
  14.         else
  15.             try {
  16.                 printSB(new DataInputStream(new FileInputStream(args[0])));
  17.             } catch (IOException ioe) {
  18.                 System.out.println("crashed :(");
  19.             }
  20.     }
  21.    
  22.     public static void printSB (DataInput s) throws IOException {
  23.         s.skipBytes(14);
  24.         printObjectTable(s, "info");
  25.         printObjectTable(s, "contents");
  26.     }
  27.    
  28.     public static void printObjectTable (DataInput s, String name) throws IOException {
  29.         System.out.printf("Object Table: %Ts\n", name);
  30.         s.skipBytes(10);
  31.         int len = s.readInt();
  32.         for (int i = 0; i < len; i++) {
  33.             int type = s.readUnsignedByte();
  34.             if (type < 9 || type == 99) {
  35.                 System.out.printf("  --invalid object type: %Tx\n", Integer.valueOf(type));
  36.                 throw new RuntimeException();
  37.             }
  38.             if (type < 99)
  39.                 printFixedFormat(s, type, i);
  40.             else
  41.                 printUserClass(s, type, i);
  42.         }
  43.     }
  44.    
  45.     public static void printFixedFormat (DataInput s, int type, int index) throws IOException {
  46.         System.out.printf("  --Object %Td: ", Integer.valueOf(index));
  47.         switch (type) {
  48.             case 9:
  49.                 byte[] str9 = new byte[s.readInt()];
  50.                 s.readFully(str9);
  51.                 System.out.printf("String (%Ts)\n", new String(str9));
  52.                 break;
  53.             case 10:
  54.                 byte[] str10 = new byte[s.readInt()];
  55.                 s.readFully(str10);
  56.                 System.out.printf("Symbol (%Ts)\n", new String(str10));
  57.                 break;
  58.             case 11:
  59.                 byte[] str11 = new byte[s.readInt()];
  60.                 s.readFully(str11);
  61.                 System.out.printf("ByteArray\n    --%Ts", toHexString(str11));
  62.                 break;
  63.             case 12:
  64.                 short[] str12 = new short[s.readInt()];
  65.                 for (int i = 0; i < str12.length; i++)
  66.                     str12[i] = s.readShort();
  67.                 System.out.printf("SoundBuffer\n    --%Ts", toHexString(str12));
  68.                 break;
  69.             case 13:
  70.                 int[] str13 = new int[s.readInt()];
  71.                 for (int i = 0; i < str13.length; i++)
  72.                     str13[i] = s.readInt();
  73.                 System.out.printf("Bitmap\n    --%Ts", toHexString(str13));
  74.                 break;
  75.             case 14:
  76.                 byte[] str14 = new byte[s.readInt()];
  77.                 s.readFully(str14);
  78.                 System.out.printf("UTF8 (%Ts)\n", new String(str14));
  79.                 break;
  80.             case 20:
  81.                 printArray(s, "Array");
  82.                 break;
  83.             case 21:
  84.                 printArray(s, "OrderedCollection");
  85.                 break;
  86.             case 22:
  87.                 printArray(s, "Set");
  88.                 break;
  89.             case 23:
  90.                 printArray(s, "IdentitySet");
  91.                 break;
  92.             case 24:
  93.                 printMap(s, "Dictionary");
  94.                 break;
  95.             case 25:
  96.                 printMap(s, "IdentityDictionary");
  97.                 break;
  98.             case 30:
  99.                 int scolor = s.readInt();
  100.                 HexFormat f31 = HexFormat.of();
  101.                 String str31 = "#" + f31.toHexDigits((short) ((scolor & 0x3FF00000) >> 20)) + f31.toHexDigits((short) ((scolor & 0x000FFC00) >> 10)) + f31.toHexDigits((short) (scolor & 0x000003FF));
  102.                 System.out.printf("Color (%Ts)\n", new String(str31));
  103.                 break;
  104.             case 31:
  105.                 int tcolor = s.readInt();
  106.                 HexFormat f32 = HexFormat.of();
  107.                 String str32 = "#" + f32.toHexDigits((short) ((tcolor & 0x3FF00000) >> 20)) + f32.toHexDigits((short) ((tcolor & 0x000FFC00) >> 10)) + f32.toHexDigits((short) (tcolor & 0x000003FF)) + f32.toHexDigits((short) s.readByte());
  108.                 System.out.printf("TranslucentColor (%Ts)\n", new String(str32));
  109.                 break;
  110.             case 32:
  111.                 System.out.printf("Point\n    --x: ");
  112.                 printInline(s);
  113.                 System.out.printf("\n    --y: ");
  114.                 printInline(s);
  115.                 System.out.println();
  116.                 break;
  117.             case 33:
  118.                 System.out.printf("Rectangle\n    --x: ");
  119.                 printInline(s);
  120.                 System.out.printf("\n    --y: ");
  121.                 printInline(s);
  122.                 System.out.printf("\n    --width (?): ");
  123.                 printInline(s);
  124.                 System.out.printf("\n    --height (?): ");
  125.                 printInline(s);
  126.                 System.out.println();
  127.                 break;
  128.             case 34:
  129.                 System.out.printf("Form\n    --width: ");
  130.                 printInline(s);
  131.                 System.out.printf("\n    --height: ");
  132.                 printInline(s);
  133.                 System.out.printf("\n    --depth (?): ");
  134.                 printInline(s);
  135.                 System.out.printf("\n    --privateOffset (?): ");
  136.                 printInline(s);
  137.                 System.out.printf("\n    --bits: ");
  138.                 printInline(s);
  139.                 System.out.println();
  140.                 break;
  141.             case 35:
  142.                 System.out.printf("ColorForm\n    --width: ");
  143.                 printInline(s);
  144.                 System.out.printf("\n    --height: ");
  145.                 printInline(s);
  146.                 System.out.printf("\n    --depth (?): ");
  147.                 printInline(s);
  148.                 System.out.printf("\n    --privateOffset (?): ");
  149.                 printInline(s);
  150.                 System.out.printf("\n    --bits: ");
  151.                 printInline(s);
  152.                 System.out.printf("\n    --colorMap (?): ");
  153.                 printInline(s);
  154.                 System.out.println();
  155.                 break;
  156.             default:
  157.                 System.out.printf("invalid type");
  158.                 throw new RuntimeException();
  159.         }
  160.     }
  161.    
  162.     public static String toHexString (byte[] v) {
  163.         if (v == null) return "null";
  164.         StringBuilder b = new StringBuilder("[");
  165.         HexFormat f = HexFormat.of();
  166.         for (int i = 0; i < v.length; ++i) {
  167.             if (i > 0) b.append(", ");
  168.             b.append("0x");
  169.             b.append(f.toHexDigits(v[i]));
  170.         }
  171.         b.append("]");
  172.         return b.toString();
  173.     }
  174.    
  175.     public static String toHexString (short[] v) {
  176.         if (v == null) return "null";
  177.         StringBuilder b = new StringBuilder("[");
  178.         HexFormat f = HexFormat.of();
  179.         for (int i = 0; i < v.length; ++i) {
  180.             if (i > 0) b.append(", ");
  181.             b.append("0x");
  182.             b.append(f.toHexDigits(v[i]));
  183.         }
  184.         b.append("]");
  185.         return b.toString();
  186.     }
  187.    
  188.     public static String toHexString (int[] v) {
  189.         if (v == null) return "null";
  190.         StringBuilder b = new StringBuilder("[");
  191.         HexFormat f = HexFormat.of();
  192.         for (int i = 0; i < v.length; ++i) {
  193.             if (i > 0) b.append(", ");
  194.             b.append("0x");
  195.             b.append(f.toHexDigits(v[i]));
  196.         }
  197.         b.append("]");
  198.         return b.toString();
  199.     }
  200.    
  201.     public static void printArray (DataInput s, String name) throws IOException {
  202.         int len = s.readInt();
  203.         if (len == 0) {
  204.             System.out.printf("%Ts []\n", name);
  205.             return;
  206.         }
  207.         System.out.printf("%Ts [", name);
  208.         for (int i = 0; i < len; i++) {
  209.             System.out.printf("\n        ");
  210.             printInline(s);
  211.         }
  212.         System.out.printf("\n    ]\n");
  213.     }
  214.    
  215.     public static void printMap (DataInput s, String name) throws IOException {
  216.         int len = s.readInt();
  217.         if (len == 0) {
  218.             System.out.printf("%Ts {}\n", name);
  219.             return;
  220.         }
  221.         System.out.printf("%Ts {", name);
  222.         for (int i = 0; i < len; i++) {
  223.             System.out.printf("\n        ");
  224.             printInline(s);
  225.             System.out.printf(": ");
  226.             printInline(s);
  227.         }
  228.         System.out.printf("\n    }\n");
  229.     }
  230.    
  231.     public static void printUserClass (DataInput s, int type, int index) throws IOException {
  232.         System.out.printf("  --Object %1$Td: %2$Ts\n", Integer.valueOf(index), getUserClassName(type));
  233.         System.out.printf("    --version: %Td\n", Integer.valueOf(s.readUnsignedByte()));
  234.         int length = s.readUnsignedByte();
  235.         System.out.printf("    --length: %Td", Integer.valueOf(length));
  236.         String[] fieldNames = getUserClassFields(type);
  237.         for (int i = 0; i < length; i++) {
  238.             String fieldName = "$$" + i;
  239.             if (i < fieldNames.length) fieldName = fieldNames[i];
  240.             System.out.printf("\n    --field %Ts: ", Integer.valueOf(i));
  241.             printInline(s);
  242.         }
  243.         System.out.println();
  244.     }
  245.    
  246.     public static void printInline (DataInput s) throws IOException {
  247.         int type = s.readUnsignedByte();
  248.         switch (type) {
  249.             case 1:
  250.                 System.out.printf("nil");
  251.                 break;
  252.             case 2:
  253.                 System.out.printf("true");
  254.                 break;
  255.             case 3:
  256.                 System.out.printf("false");
  257.                 break;
  258.             case 4:
  259.                 System.out.printf("SmallInteger (%Td)", Integer.valueOf(s.readInt()));
  260.                 break;
  261.             case 5:
  262.                 System.out.printf("SmallInteger16 (%Td)", Integer.valueOf(s.readShort()));
  263.                 break;
  264.             case 6:
  265.                 byte[] array6 = new byte[s.readUnsignedShort()];
  266.                 s.readFully(array6);
  267.                 System.out.printf("LargePositiveInteger (%Ts)", new BigInteger(1, array6));
  268.                 break;
  269.             case 7:
  270.                 byte[] array7 = new byte[s.readUnsignedShort()];
  271.                 s.readFully(array7);
  272.                 System.out.printf("LargePositiveInteger (%Ts)", new BigInteger(-1, array7));
  273.                 break;
  274.             case 8:
  275.                 System.out.printf("Float (%Tf)", Double.valueOf(s.readDouble()));
  276.                 break;
  277.             case 99:
  278.                 byte[] array99 = new byte[s.readUnsignedShort()];
  279.                 s.readFully(array99);
  280.                 System.out.printf("Object Reference @%Td", ByteBuffer.allocate(4).put((byte) 0).put(array99).getInt());
  281.                 break;
  282.             default:
  283.                 System.out.printf("illegal inline type (%Td)", type);
  284.                 throw new RuntimeException();
  285.         }
  286.     }
  287.    
  288.     public static final Map.Entry<String, String[]>[] USER_CLASS_FORMATS = new Map.Entry[] {
  289.         Map.<String, String[]>entry("Morph", new String[] {
  290.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  291.         Map.<String, String[]>entry("BorderedMorph", new String[] {
  292.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor" }),
  293.         Map.<String, String[]>entry("RectangleMorph", new String[] {
  294.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor" }),
  295.         Map.<String, String[]>entry("EllipseMorph", new String[] {
  296.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor" }),
  297.         Map.<String, String[]>entry("AlignmentMorph", new String[] {
  298.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor",
  299.             "orientation", "centering", "hResizing", "vResizing", "inset" }),
  300.         Map.<String, String[]>entry("StringMorph", new String[] {
  301.             "bounds", "owner", "submorphs", "color", "flags", "properties", "font with size", "emphasis",
  302.             "contents" }),
  303.         Map.<String, String[]>entry("UpdatingStringMorph", new String[] {
  304.             "bounds", "owner", "submorphs", "color", "flags", "properties", "font with size", "emphasis",
  305.             "contents" }),
  306.         Map.<String, String[]>entry("SimpleSliderMorph", new String[] {
  307.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor", "slider",
  308.             "value", "setValueSelector", "sliderShadow", "sliderColor", "descending", "model", "target",
  309.             "actionSelector", "arguments", "actWhen" }),
  310.         Map.<String, String[]>entry("SimpleButtonMorph", new String[] {
  311.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor",
  312.             "target", "actionSelector", "arguments", "actWhen" }),
  313.         Map.<String, String[]>entry("SampledSound", new String[] {
  314.             "envelopes", "scaledVol", "initialCount", "samples", "originalSaplingRate", "samplesSize",
  315.             "scaledIncrement", "scaledInitialIndex" }),
  316.         Map.<String, String[]>entry("ImageMorph", new String[] {
  317.             "bounds", "owner", "submorphs", "color", "flags", "properties", "form", "transparency" }),
  318.         Map.<String, String[]>entry("SketchMorph", new String[] {
  319.             "bounds", "owner", "submorphs", "color", "flags", "properties", "originalForm", "rotationCenter",
  320.             "rotationDegrees", "rotationStyle", "scalePoint", "offsetWhenRotated" }),
  321.         null,
  322.         null,
  323.         null,
  324.         null,
  325.         null,
  326.         null,
  327.         null,
  328.         null,
  329.         null,
  330.         null,
  331.         null,
  332.         Map.<String, String[]>entry("SensorBoardMorph", new String[] {
  333.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  334.         Map.<String, String[]>entry("ScratchSpriteMorph", new String[] {
  335.             "bounds", "owner", "submorphs", "color", "flags", "properties", "objName", "vars", "blocksBin",
  336.             "isClone", "media", "costume", "visibility", "scalePoint", "rotationDegrees", "rotationStyle",
  337.             "volume", "tempoBPM", "draggable", "sceneStates", "lists" }),
  338.         Map.<String, String[]>entry("ScratchStageMorph", new String[] {
  339.             "bounds", "owner", "submorphs", "color", "flags", "properties", "objName", "vars", "blocksBin",
  340.             "isClone", "media", "costume", "zoom", "hPan", "vPan", "obsoleteSavedState", "sprites", "volume",
  341.             "tempoBPM", "sceneStates", "lists" }),
  342.         null,
  343.         null,
  344.         null,
  345.         null,
  346.         null,
  347.         null,
  348.         null,
  349.         null,
  350.         null,
  351.         null,
  352.         null,
  353.         null,
  354.         null,
  355.         null,
  356.         Map.<String, String[]>entry("ChoiceArgMorph", new String[] {
  357.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  358.         Map.<String, String[]>entry("ColorArgMorph", new String[] {
  359.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  360.         Map.<String, String[]>entry("ExpressionArgMorph", new String[] {
  361.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  362.         null,
  363.         null,
  364.         Map.<String, String[]>entry("SpriteArgMorph", new String[] {
  365.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  366.         null,
  367.         Map.<String, String[]>entry("BlockMorph", new String[] {
  368.             "bounds", "owner", "submorphs", "color", "flags", "properties", "isSpecialForm", "oldColor" }),
  369.         Map.<String, String[]>entry("CommandBlockMorph", new String[] {
  370.             "bounds", "owner", "submorphs", "color", "flags", "properties", "isSpecialForm", "oldColor",
  371.             "commandSpec", "argMorphs", "titleMorph", "reciever", "selector", "isReporter", "isTimed",
  372.             "wantsName", "wantsPossesion" }),
  373.         Map.<String, String[]>entry("CBlockMorph", new String[] {
  374.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  375.         null,
  376.         Map.<String, String[]>entry("HatBlockMorph", new String[] {
  377.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  378.         null,
  379.         Map.<String, String[]>entry("ScratchScriptsMorph", new String[] {
  380.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor" }),
  381.         Map.<String, String[]>entry("ScratchSliderMorph", new String[] {
  382.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  383.         Map.<String, String[]>entry("AlignmentMorph", new String[] {
  384.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor",
  385.             "orientation", "centering", "hResizing", "vResizing", "inset", "titleMorph", "readout", "readoutFrame",
  386.             "scratchSlider", "watcher", "isSpriteSpecific", "$$19", "sliderMin", "sliderMax", "isLarge" }),
  387.         null,
  388.         Map.<String, String[]>entry("SetterBlockMorph", new String[] {
  389.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  390.         Map.<String, String[]>entry("EventHatMorph", new String[] {
  391.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  392.         null,
  393.         Map.<String, String[]>entry("VariableBlockMorph", new String[] {
  394.             "bounds", "owner", "submorphs", "color", "flags", "properties", "isSpecialForm", "oldColor",
  395.             "commandSpec", "argMorphs", "titleMorph", "reciever", "selector", "isReporter", "isTimed",
  396.             "wantsName", "wantsPossesion", "isBoolean" }),
  397.         null,
  398.         Map.<String, String[]>entry("ImageMedia", new String[] {
  399.             "mediaName", "form", "rotationCenter", "textBox", "jpegBytes", "compositeForm" }),
  400.         Map.<String, String[]>entry("MovieMedia", new String[] {
  401.             "mediaName", "fileName", "fade", "fadeColor", "zoom", "hPan", "vPan", "msecsPerFrame", "currentFrame",
  402.             "moviePlaying" }),
  403.         Map.<String, String[]>entry("SoundMedia", new String[] {
  404.             "mediaName", "originalSound", "volume", "balance", "compressedSampleRate", "compressedBitsPerSample",
  405.             "compressedData" }),
  406.         Map.<String, String[]>entry("KeyEventHatMorph", new String[] {
  407.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  408.         Map.<String, String[]>entry("BooleanArgMorph", new String[] {
  409.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  410.         Map.<String, String[]>entry("EventTitleMorph", new String[] {
  411.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  412.         Map.<String, String[]>entry("MouseClickEventHatMorph", new String[] {
  413.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  414.         Map.<String, String[]>entry("ExpressionArgMorphWithMenu", new String[] {
  415.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  416.         Map.<String, String[]>entry("ReporterBlockMorph", new String[] {
  417.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  418.         Map.<String, String[]>entry("MultilineStringMorph", new String[] {
  419.             "bounds", "owner", "submorphs", "color", "flags", "properties" }),
  420.         Map.<String, String[]>entry("ToggleButton", new String[] {
  421.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor",
  422.             "target", "actionSelector", "arguments", "actWhen" }),
  423.         Map.<String, String[]>entry("WatcherReadoutFrameMorph", new String[] {
  424.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor" }),
  425.         Map.<String, String[]>entry("WatcherSliderMorph", new String[] {
  426.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor", "slider",
  427.             "value", "setValueSelector", "sliderShadow", "sliderColor", "descending", "model", "target",
  428.             "actionSelector", "arguments", "actWhen" }),
  429.         Map.<String, String[]>entry("ScratchListMorph", new String[] {
  430.             "bounds", "owner", "submorphs", "color", "flags", "properties", "borderWidth", "borderColor",
  431.             "listName", "cellMorphs", "target" }),
  432.         Map.<String, String[]>entry("ScrollingStringMorph", new String[] {
  433.             "bounds", "owner", "submorphs", "color", "flags", "properties" })
  434.         };
  435.    
  436.     public static String getUserClassName (int type) {
  437.         if (type < 100 || type > 176) return "UserClassType" + type;
  438.         return USER_CLASS_FORMATS[type - 100].getKey();
  439.     }
  440.    
  441.     public static String[] getUserClassFields (int type) {
  442.         if (type < 100 || type > 176) return new String[0];
  443.         return USER_CLASS_FORMATS[type - 100].getValue();
  444.     }
  445. }
Advertisement
Add Comment
Please, Sign In to add comment