0001: /*
0002: * BinaryCmd.java --
0003: *
0004: * Implements the built-in "binary" Tcl command.
0005: *
0006: * Copyright (c) 1999 Christian Krone.
0007: * Copyright (c) 1997 by Sun Microsystems, Inc.
0008: *
0009: * See the file "license.terms" for information on usage and
0010: * redistribution of this file, and for a DISCLAIMER OF ALL
0011: * WARRANTIES.
0012: *
0013: * RCS: @(#) $Id: BinaryCmd.java,v 1.3 2005/07/22 04:47:24 mdejong Exp $
0014: *
0015: */
0016:
0017: package tcl.lang;
0018:
0019: import java.text.*;
0020:
0021: /*
0022: * This class implements the built-in "binary" command in Tcl.
0023: */
0024:
0025: class BinaryCmd implements Command {
0026:
0027: static final private String validCmds[] = { "format", "scan", };
0028:
0029: static final private int CMD_FORMAT = 0;
0030: static final private int CMD_SCAN = 1;
0031:
0032: // The following constants are used by GetFormatSpec to indicate various
0033: // special conditions in the parsing of a format specifier.
0034:
0035: // Use all elements in the argument.
0036: static final private int BINARY_ALL = -1;
0037: // No count was specified in format.
0038: static final private int BINARY_NOCOUNT = -2;
0039: // End of format was found.
0040: static final private char FORMAT_END = ' ';
0041:
0042: /*
0043: *----------------------------------------------------------------------
0044: *
0045: * cmdProc --
0046: *
0047: * This procedure is invoked as part of the Command interface to
0048: * process the "binary" Tcl command. See the user documentation
0049: * for details on what it does.
0050: *
0051: * Results:
0052: * None.
0053: *
0054: * Side effects:
0055: * See the user documentation.
0056: *
0057: *----------------------------------------------------------------------
0058: */
0059:
0060: public void cmdProc(Interp interp, // Current interpreter.
0061: TclObject[] argv) // Argument list.
0062: throws TclException // A standard Tcl exception.
0063: {
0064: int arg; // Index of next argument to consume.
0065: char[] format = null; // User specified format string.
0066: char cmd; // Current format character.
0067: int cursor; // Current position within result buffer.
0068: int maxPos; // Greatest position within result buffer that
0069: // cursor has visited.
0070: int value = 0; // Current integer value to be packed.
0071: // Initialized to avoid compiler warning.
0072: int offset, size = 0, length, index;
0073:
0074: if (argv.length < 2) {
0075: throw new TclNumArgsException(interp, 1, argv,
0076: "option ?arg arg ...?");
0077: }
0078: int cmdIndex = TclIndex.get(interp, argv[1], validCmds,
0079: "option", 0);
0080:
0081: switch (cmdIndex) {
0082: case CMD_FORMAT: {
0083: if (argv.length < 3) {
0084: throw new TclNumArgsException(interp, 2, argv,
0085: "formatString ?arg arg ...?");
0086: }
0087:
0088: // To avoid copying the data, we format the string in two passes.
0089: // The first pass computes the size of the output buffer. The
0090: // second pass places the formatted data into the buffer.
0091:
0092: format = argv[2].toString().toCharArray();
0093: arg = 3;
0094: length = 0;
0095: offset = 0;
0096: ParsePosition parsePos = new ParsePosition(0);
0097:
0098: while ((cmd = GetFormatSpec(format, parsePos)) != FORMAT_END) {
0099: int count = GetFormatCount(format, parsePos);
0100:
0101: switch (cmd) {
0102: case 'a':
0103: case 'A':
0104: case 'b':
0105: case 'B':
0106: case 'h':
0107: case 'H': {
0108: // For string-type specifiers, the count corresponds
0109: // to the number of bytes in a single argument.
0110:
0111: if (arg >= argv.length) {
0112: missingArg(interp);
0113: }
0114: if (count == BINARY_ALL) {
0115: count = TclByteArray.getLength(interp,
0116: argv[arg]);
0117: } else if (count == BINARY_NOCOUNT) {
0118: count = 1;
0119: }
0120: arg++;
0121: switch (cmd) {
0122: case 'a':
0123: case 'A':
0124: offset += count;
0125: break;
0126: case 'b':
0127: case 'B':
0128: offset += (count + 7) / 8;
0129: break;
0130: case 'h':
0131: case 'H':
0132: offset += (count + 1) / 2;
0133: break;
0134: }
0135: break;
0136: }
0137: case 'c':
0138: case 's':
0139: case 'S':
0140: case 'i':
0141: case 'I':
0142: case 'f':
0143: case 'd': {
0144: if (arg >= argv.length) {
0145: missingArg(interp);
0146: }
0147: switch (cmd) {
0148: case 'c':
0149: size = 1;
0150: break;
0151: case 's':
0152: case 'S':
0153: size = 2;
0154: break;
0155: case 'i':
0156: case 'I':
0157: size = 4;
0158: break;
0159: case 'f':
0160: size = 4;
0161: break;
0162: case 'd':
0163: size = 8;
0164: break;
0165: }
0166:
0167: // For number-type specifiers, the count corresponds
0168: // to the number of elements in the list stored in
0169: // a single argument. If no count is specified, then
0170: // the argument is taken as a single non-list value.
0171:
0172: if (count == BINARY_NOCOUNT) {
0173: arg++;
0174: count = 1;
0175: } else {
0176: int listc = TclList.getLength(interp,
0177: argv[arg++]);
0178: if (count == BINARY_ALL) {
0179: count = listc;
0180: } else if (count > listc) {
0181: throw new TclException(interp,
0182: "number of elements in list"
0183: + " does not match count");
0184: }
0185: }
0186: offset += count * size;
0187: break;
0188: }
0189: case 'x': {
0190: if (count == BINARY_ALL) {
0191: throw new TclException(
0192: interp,
0193: "cannot use \"*\""
0194: + " in format string with \"x\"");
0195: }
0196: if (count == BINARY_NOCOUNT) {
0197: count = 1;
0198: }
0199: offset += count;
0200: break;
0201: }
0202: case 'X': {
0203: if (count == BINARY_NOCOUNT) {
0204: count = 1;
0205: }
0206: if ((count > offset) || (count == BINARY_ALL)) {
0207: count = offset;
0208: }
0209: if (offset > length) {
0210: length = offset;
0211: }
0212: offset -= count;
0213: break;
0214: }
0215: case '@': {
0216: if (offset > length) {
0217: length = offset;
0218: }
0219: if (count == BINARY_ALL) {
0220: offset = length;
0221: } else if (count == BINARY_NOCOUNT) {
0222: alephWithoutCount(interp);
0223: } else {
0224: offset = count;
0225: }
0226: break;
0227: }
0228: default: {
0229: badField(interp, cmd);
0230: }
0231: }
0232: }
0233: if (offset > length) {
0234: length = offset;
0235: }
0236: if (length == 0) {
0237: return;
0238: }
0239:
0240: // Prepare the result object by preallocating the calculated
0241: // number of bytes and filling with nulls.
0242:
0243: TclObject resultObj = TclByteArray.newInstance();
0244: byte[] resultBytes = TclByteArray.setLength(interp,
0245: resultObj, length);
0246: interp.setResult(resultObj);
0247:
0248: // Pack the data into the result object. Note that we can skip
0249: // the error checking during this pass, since we have already
0250: // parsed the string once.
0251:
0252: arg = 3;
0253: cursor = 0;
0254: maxPos = cursor;
0255: parsePos.setIndex(0);
0256:
0257: while ((cmd = GetFormatSpec(format, parsePos)) != FORMAT_END) {
0258: int count = GetFormatCount(format, parsePos);
0259:
0260: if ((count == 0) && (cmd != '@')) {
0261: arg++;
0262: continue;
0263: }
0264:
0265: switch (cmd) {
0266: case 'a':
0267: case 'A': {
0268: byte pad = (cmd == 'a') ? (byte) 0 : (byte) ' ';
0269: byte[] bytes = TclByteArray.getBytes(interp,
0270: argv[arg++]);
0271: length = bytes.length;
0272:
0273: if (count == BINARY_ALL) {
0274: count = length;
0275: } else if (count == BINARY_NOCOUNT) {
0276: count = 1;
0277: }
0278: if (length >= count) {
0279: System.arraycopy(bytes, 0, resultBytes, cursor,
0280: count);
0281: } else {
0282: System.arraycopy(bytes, 0, resultBytes, cursor,
0283: length);
0284: for (int ix = 0; ix < count - length; ix++) {
0285: resultBytes[cursor + length + ix] = pad;
0286: }
0287: }
0288: cursor += count;
0289: break;
0290: }
0291: case 'b':
0292: case 'B': {
0293: char[] str = argv[arg++].toString().toCharArray();
0294: if (count == BINARY_ALL) {
0295: count = str.length;
0296: } else if (count == BINARY_NOCOUNT) {
0297: count = 1;
0298: }
0299: int last = cursor + ((count + 7) / 8);
0300: if (count > str.length) {
0301: count = str.length;
0302: }
0303: if (cmd == 'B') {
0304: for (offset = 0; offset < count; offset++) {
0305: value <<= 1;
0306: if (str[offset] == '1') {
0307: value |= 1;
0308: } else if (str[offset] != '0') {
0309: expectedButGot(interp, "binary",
0310: new String(str));
0311: }
0312: if (((offset + 1) % 8) == 0) {
0313: resultBytes[cursor++] = (byte) value;
0314: value = 0;
0315: }
0316: }
0317: } else {
0318: for (offset = 0; offset < count; offset++) {
0319: value >>= 1;
0320: if (str[offset] == '1') {
0321: value |= 128;
0322: } else if (str[offset] != '0') {
0323: expectedButGot(interp, "binary",
0324: new String(str));
0325: }
0326: if (((offset + 1) % 8) == 0) {
0327: resultBytes[cursor++] = (byte) value;
0328: value = 0;
0329: }
0330: }
0331: }
0332: if ((offset % 8) != 0) {
0333: if (cmd == 'B') {
0334: value <<= 8 - (offset % 8);
0335: } else {
0336: value >>= 8 - (offset % 8);
0337: }
0338: resultBytes[cursor++] = (byte) value;
0339: }
0340: while (cursor < last) {
0341: resultBytes[cursor++] = 0;
0342: }
0343: break;
0344: }
0345: case 'h':
0346: case 'H': {
0347: char[] str = argv[arg++].toString().toCharArray();
0348: if (count == BINARY_ALL) {
0349: count = str.length;
0350: } else if (count == BINARY_NOCOUNT) {
0351: count = 1;
0352: }
0353: int last = cursor + ((count + 1) / 2);
0354: if (count > str.length) {
0355: count = str.length;
0356: }
0357: if (cmd == 'H') {
0358: for (offset = 0; offset < count; offset++) {
0359: value <<= 4;
0360: int c = Character.digit(str[offset], 16);
0361: if (c < 0) {
0362: expectedButGot(interp, "hexadecimal",
0363: new String(str));
0364: }
0365: value |= (c & 0xf);
0366: if ((offset % 2) != 0) {
0367: resultBytes[cursor++] = (byte) value;
0368: value = 0;
0369: }
0370: }
0371: } else {
0372: for (offset = 0; offset < count; offset++) {
0373: value >>= 4;
0374: int c = Character.digit(str[offset], 16);
0375: if (c < 0) {
0376: expectedButGot(interp, "hexadecimal",
0377: new String(str));
0378: }
0379: value |= ((c << 4) & 0xf0);
0380: if ((offset % 2) != 0) {
0381: resultBytes[cursor++] = (byte) value;
0382: value = 0;
0383: }
0384: }
0385: }
0386: if ((offset % 2) != 0) {
0387: if (cmd == 'H') {
0388: value <<= 4;
0389: } else {
0390: value >>= 4;
0391: }
0392: resultBytes[cursor++] = (byte) value;
0393: }
0394: while (cursor < last) {
0395: resultBytes[cursor++] = 0;
0396: }
0397: break;
0398: }
0399: case 'c':
0400: case 's':
0401: case 'S':
0402: case 'i':
0403: case 'I':
0404: case 'f':
0405: case 'd': {
0406: TclObject[] listv;
0407:
0408: if (count == BINARY_NOCOUNT) {
0409: listv = new TclObject[1];
0410: listv[0] = argv[arg++];
0411: count = 1;
0412: } else {
0413: listv = TclList
0414: .getElements(interp, argv[arg++]);
0415: if (count == BINARY_ALL) {
0416: count = listv.length;
0417: }
0418: }
0419: for (int ix = 0; ix < count; ix++) {
0420: cursor = FormatNumber(interp, cmd, listv[ix],
0421: resultBytes, cursor);
0422: }
0423: break;
0424: }
0425: case 'x': {
0426: if (count == BINARY_NOCOUNT) {
0427: count = 1;
0428: }
0429: for (int ix = 0; ix < count; ix++) {
0430: resultBytes[cursor++] = 0;
0431: }
0432: break;
0433: }
0434: case 'X': {
0435: if (cursor > maxPos) {
0436: maxPos = cursor;
0437: }
0438: if (count == BINARY_NOCOUNT) {
0439: count = 1;
0440: }
0441: if (count == BINARY_ALL || count > cursor) {
0442: cursor = 0;
0443: } else {
0444: cursor -= count;
0445: }
0446: break;
0447: }
0448: case '@': {
0449: if (cursor > maxPos) {
0450: maxPos = cursor;
0451: }
0452: if (count == BINARY_ALL) {
0453: cursor = maxPos;
0454: } else {
0455: cursor = count;
0456: }
0457: break;
0458: }
0459: }
0460: }
0461: break;
0462: }
0463: case CMD_SCAN: {
0464: if (argv.length < 4) {
0465: throw new TclNumArgsException(interp, 2, argv,
0466: "value formatString ?varName varName ...?");
0467: }
0468: byte[] src = TclByteArray.getBytes(interp, argv[2]);
0469: length = src.length;
0470: format = argv[3].toString().toCharArray();
0471: arg = 4;
0472: cursor = 0;
0473: offset = 0;
0474: ParsePosition parsePos = new ParsePosition(0);
0475:
0476: while ((cmd = GetFormatSpec(format, parsePos)) != FORMAT_END) {
0477: int count = GetFormatCount(format, parsePos);
0478:
0479: switch (cmd) {
0480: case 'a':
0481: case 'A': {
0482: if (arg >= argv.length) {
0483: missingArg(interp);
0484: }
0485: if (count == BINARY_ALL) {
0486: count = length - offset;
0487: } else {
0488: if (count == BINARY_NOCOUNT) {
0489: count = 1;
0490: }
0491: if (count > length - offset) {
0492: break;
0493: }
0494: }
0495:
0496: size = count;
0497:
0498: // Trim trailing nulls and spaces, if necessary.
0499:
0500: if (cmd == 'A') {
0501: while (size > 0) {
0502: if (src[offset + size - 1] != '\0'
0503: && src[offset + size - 1] != ' ') {
0504: break;
0505: }
0506: size--;
0507: }
0508: }
0509:
0510: interp.setVar(argv[arg++], TclByteArray
0511: .newInstance(src, offset, size), 0);
0512:
0513: offset += count;
0514: break;
0515: }
0516: case 'b':
0517: case 'B': {
0518: if (arg >= argv.length) {
0519: missingArg(interp);
0520: }
0521: if (count == BINARY_ALL) {
0522: count = (length - offset) * 8;
0523: } else {
0524: if (count == BINARY_NOCOUNT) {
0525: count = 1;
0526: }
0527: if (count > (length - offset) * 8) {
0528: break;
0529: }
0530: }
0531: StringBuffer s = new StringBuffer(count);
0532: int this Offset = offset;
0533:
0534: if (cmd == 'b') {
0535: for (int ix = 0; ix < count; ix++) {
0536: if ((ix % 8) != 0) {
0537: value >>= 1;
0538: } else {
0539: value = src[this Offset++];
0540: }
0541: s.append((value & 1) != 0 ? '1' : '0');
0542: }
0543: } else {
0544: for (int ix = 0; ix < count; ix++) {
0545: if ((ix % 8) != 0) {
0546: value <<= 1;
0547: } else {
0548: value = src[this Offset++];
0549: }
0550: s.append((value & 0x80) != 0 ? '1' : '0');
0551: }
0552: }
0553:
0554: interp.setVar(argv[arg++], TclString.newInstance(s
0555: .toString()), 0);
0556:
0557: offset += (count + 7) / 8;
0558: break;
0559: }
0560: case 'h':
0561: case 'H': {
0562: if (arg >= argv.length) {
0563: missingArg(interp);
0564: }
0565: if (count == BINARY_ALL) {
0566: count = (length - offset) * 2;
0567: } else {
0568: if (count == BINARY_NOCOUNT) {
0569: count = 1;
0570: }
0571: if (count > (length - offset) * 2) {
0572: break;
0573: }
0574: }
0575: StringBuffer s = new StringBuffer(count);
0576: int this Offset = offset;
0577:
0578: if (cmd == 'h') {
0579: for (int ix = 0; ix < count; ix++) {
0580: if ((ix % 2) != 0) {
0581: value >>= 4;
0582: } else {
0583: value = src[this Offset++];
0584: }
0585: s.append(Character
0586: .forDigit(value & 0xf, 16));
0587: }
0588: } else {
0589: for (int ix = 0; ix < count; ix++) {
0590: if ((ix % 2) != 0) {
0591: value <<= 4;
0592: } else {
0593: value = src[this Offset++];
0594: }
0595: s.append(Character.forDigit(
0596: value >> 4 & 0xf, 16));
0597: }
0598: }
0599:
0600: interp.setVar(argv[arg++], TclString.newInstance(s
0601: .toString()), 0);
0602:
0603: offset += (count + 1) / 2;
0604: break;
0605: }
0606: case 'c':
0607: case 's':
0608: case 'S':
0609: case 'i':
0610: case 'I':
0611: case 'f':
0612: case 'd': {
0613: if (arg >= argv.length) {
0614: missingArg(interp);
0615: }
0616: switch (cmd) {
0617: case 'c':
0618: size = 1;
0619: break;
0620: case 's':
0621: case 'S':
0622: size = 2;
0623: break;
0624: case 'i':
0625: case 'I':
0626: size = 4;
0627: break;
0628: case 'f':
0629: size = 4;
0630: break;
0631: case 'd':
0632: size = 8;
0633: break;
0634: }
0635: TclObject valueObj;
0636: if (count == BINARY_NOCOUNT) {
0637: if (length - offset < size) {
0638: break;
0639: }
0640: valueObj = ScanNumber(src, offset, cmd);
0641: offset += size;
0642: } else {
0643: if (count == BINARY_ALL) {
0644: count = (length - offset) / size;
0645: }
0646: if (length - offset < count * size) {
0647: break;
0648: }
0649: valueObj = TclList.newInstance();
0650: int this Offset = offset;
0651: for (int ix = 0; ix < count; ix++) {
0652: TclList.append(null, valueObj, ScanNumber(
0653: src, this Offset, cmd));
0654: this Offset += size;
0655: }
0656: offset += count * size;
0657: }
0658:
0659: interp.setVar(argv[arg++], valueObj, 0);
0660:
0661: break;
0662: }
0663: case 'x': {
0664: if (count == BINARY_NOCOUNT) {
0665: count = 1;
0666: }
0667: if (count == BINARY_ALL || count > length - offset) {
0668: offset = length;
0669: } else {
0670: offset += count;
0671: }
0672: break;
0673: }
0674: case 'X': {
0675: if (count == BINARY_NOCOUNT) {
0676: count = 1;
0677: }
0678: if (count == BINARY_ALL || count > offset) {
0679: offset = 0;
0680: } else {
0681: offset -= count;
0682: }
0683: break;
0684: }
0685: case '@': {
0686: if (count == BINARY_NOCOUNT) {
0687: alephWithoutCount(interp);
0688: }
0689: if (count == BINARY_ALL || count > length) {
0690: offset = length;
0691: } else {
0692: offset = count;
0693: }
0694: break;
0695: }
0696: default: {
0697: badField(interp, cmd);
0698: }
0699: }
0700: }
0701:
0702: // Set the result to the last position of the cursor.
0703:
0704: interp.setResult(arg - 4);
0705: }
0706: }
0707: }
0708:
0709: /*
0710: *----------------------------------------------------------------------
0711: *
0712: * GetFormatSpec --
0713: *
0714: * This function parses the format strings used in the binary
0715: * format and scan commands.
0716: *
0717: * Results:
0718: * Moves the parsePos to the start of the next command. Returns
0719: * the current command character or FORMAT_END if the string did
0720: * not have a format specifier.
0721: *
0722: * Side effects:
0723: * None.
0724: *
0725: *----------------------------------------------------------------------
0726: */
0727:
0728: private char GetFormatSpec(char[] format, // Format string.
0729: ParsePosition parsePos) // Current position in input.
0730: {
0731: int ix = parsePos.getIndex();
0732:
0733: // Skip any leading blanks.
0734:
0735: while (ix < format.length && format[ix] == ' ') {
0736: ix++;
0737: }
0738:
0739: // The string was empty, except for whitespace, so fail.
0740:
0741: if (ix >= format.length) {
0742: parsePos.setIndex(ix);
0743: return FORMAT_END;
0744: }
0745:
0746: // Extract the command character.
0747:
0748: parsePos.setIndex(ix + 1);
0749:
0750: return format[ix++];
0751: }
0752:
0753: /*
0754: *----------------------------------------------------------------------
0755: *
0756: * GetFormatCount --
0757: *
0758: * This function parses the format strings used in the binary
0759: * format and scan commands.
0760: *
0761: * Results:
0762: * Moves the formatPtr to the start of the next command. Returns
0763: * the current command count. The count is set to BINARY_ALL if the
0764: * count character was '*' or BINARY_NOCOUNT if no count was
0765: * specified.
0766: *
0767: * Side effects:
0768: * None.
0769: *
0770: *----------------------------------------------------------------------
0771: */
0772:
0773: private int GetFormatCount(char[] format, // Format string.
0774: ParsePosition parsePos) // Current position in input.
0775: {
0776: int ix = parsePos.getIndex();
0777:
0778: // Extract any trailing digits or '*'.
0779:
0780: if (ix < format.length && format[ix] == '*') {
0781: parsePos.setIndex(ix + 1);
0782: return BINARY_ALL;
0783: } else if (ix < format.length && Character.isDigit(format[ix])) {
0784: int length = 1;
0785: while (ix + length < format.length
0786: && Character.isDigit(format[ix + length])) {
0787: length++;
0788: }
0789: parsePos.setIndex(ix + length);
0790: return Integer.parseInt(new String(format, ix, length));
0791: } else {
0792: return BINARY_NOCOUNT;
0793: }
0794: }
0795:
0796: /**
0797: *----------------------------------------------------------------------
0798: *
0799: * FormatNumber --
0800: *
0801: * This method is called by the binary cmdProc to format a number
0802: * into a location pointed at by cursor.
0803: *
0804: * Results:
0805: * None
0806: *
0807: * Side effects:
0808: * None.
0809: *
0810: *----------------------------------------------------------------------
0811: */
0812:
0813: static int FormatNumber(Interp interp, // Current interpreter.
0814: char type, // Type of number to format.
0815: TclObject src, // Number to format.
0816: byte[] resultBytes, int cursor) throws TclException // A standard Tcl exception.
0817: {
0818: if (type == 'd') {
0819: double dvalue = TclDouble.get(interp, src);
0820: //System.out.println("double value is \"" + dvalue + "\"");
0821: long lvalue = Double.doubleToLongBits(dvalue);
0822: //System.out.println("long hex value is \"" + Long.toHexString(lvalue) + "\"");
0823: for (int ix = 7; ix >= 0; ix--) {
0824: resultBytes[cursor++] = (byte) (lvalue >> ix * 8);
0825: //byte b = resultBytes[cursor - 1];
0826: //System.out.println("index " + ix + " is " + Integer.toHexString(b & 0xff));
0827: }
0828: } else if (type == 'f') {
0829: float fvalue;
0830: double dvalue = TclDouble.get(interp, src);
0831: //System.out.println("double value is \"" + dvalue + "\"");
0832: // Restrict the double value to the valid float range
0833: if (dvalue == Double.POSITIVE_INFINITY) {
0834: fvalue = Float.POSITIVE_INFINITY;
0835: } else if (dvalue == Double.NEGATIVE_INFINITY) {
0836: fvalue = Float.NEGATIVE_INFINITY;
0837: } else if (Math.abs(dvalue) > (double) Float.MAX_VALUE) {
0838: fvalue = (dvalue >= 0.0) ? Float.MAX_VALUE
0839: : -Float.MAX_VALUE;
0840: } else if (Math.abs(dvalue) < (double) Float.MIN_VALUE) {
0841: fvalue = (dvalue >= 0.0) ? 0.0f : -0.0f;
0842: } else {
0843: fvalue = (float) dvalue;
0844: }
0845: //System.out.println("float value is \"" + fvalue + "\"");
0846: int ivalue = Float.floatToIntBits(fvalue);
0847: //System.out.println("int hex value is \"" + Integer.toHexString(ivalue) + "\"");
0848: for (int ix = 3; ix >= 0; ix--) {
0849: resultBytes[cursor++] = (byte) (ivalue >> ix * 8);
0850: //byte b = resultBytes[cursor - 1];
0851: //System.out.println("index " + ix + " is " + Integer.toHexString(b & 0xff));
0852: }
0853: } else {
0854: int value = TclInteger.get(interp, src);
0855:
0856: if (type == 'c') {
0857: resultBytes[cursor++] = (byte) value;
0858: } else if (type == 's') {
0859: resultBytes[cursor++] = (byte) value;
0860: resultBytes[cursor++] = (byte) (value >> 8);
0861: } else if (type == 'S') {
0862: resultBytes[cursor++] = (byte) (value >> 8);
0863: resultBytes[cursor++] = (byte) value;
0864: } else if (type == 'i') {
0865: resultBytes[cursor++] = (byte) value;
0866: resultBytes[cursor++] = (byte) (value >> 8);
0867: resultBytes[cursor++] = (byte) (value >> 16);
0868: resultBytes[cursor++] = (byte) (value >> 24);
0869: } else if (type == 'I') {
0870: resultBytes[cursor++] = (byte) (value >> 24);
0871: resultBytes[cursor++] = (byte) (value >> 16);
0872: resultBytes[cursor++] = (byte) (value >> 8);
0873: resultBytes[cursor++] = (byte) value;
0874: }
0875: }
0876: return cursor;
0877: }
0878:
0879: /**
0880: *----------------------------------------------------------------------
0881: *
0882: * ScanNumber --
0883: *
0884: * This routine is called by Tcl_BinaryObjCmd to scan a number
0885: * out of a buffer.
0886: *
0887: * Results:
0888: * Returns a newly created object containing the scanned number.
0889: * This object has a ref count of zero.
0890: *
0891: * Side effects:
0892: * None.
0893: *
0894: *----------------------------------------------------------------------
0895: */
0896:
0897: private static TclObject ScanNumber(byte[] src, // Buffer to scan number from.
0898: int pos, //
0899: int type) // Format character from "binary scan"
0900: {
0901: switch (type) {
0902: case 'c': {
0903: return TclInteger.newInstance((int) src[pos]);
0904: }
0905: case 's': {
0906: short value = (short) ((src[pos] & 0xff) + ((src[pos + 1] & 0xff) << 8));
0907: return TclInteger.newInstance((int) value);
0908: }
0909: case 'S': {
0910: short value = (short) ((src[pos + 1] & 0xff) + ((src[pos] & 0xff) << 8));
0911: return TclInteger.newInstance((int) value);
0912: }
0913: case 'i': {
0914: int value = (src[pos] & 0xff)
0915: + ((src[pos + 1] & 0xff) << 8)
0916: + ((src[pos + 2] & 0xff) << 16)
0917: + ((src[pos + 3] & 0xff) << 24);
0918: return TclInteger.newInstance(value);
0919: }
0920: case 'I': {
0921: int value = (src[pos + 3] & 0xff)
0922: + ((src[pos + 2] & 0xff) << 8)
0923: + ((src[pos + 1] & 0xff) << 16)
0924: + ((src[pos] & 0xff) << 24);
0925: return TclInteger.newInstance(value);
0926: }
0927: case 'f': {
0928: int value = (src[pos + 3] & 0xff)
0929: + ((src[pos + 2] & 0xff) << 8)
0930: + ((src[pos + 1] & 0xff) << 16)
0931: + ((src[pos] & 0xff) << 24);
0932: return TclDouble.newInstance(Float.intBitsToFloat(value));
0933: }
0934: case 'd': {
0935: long value = (((long) src[pos + 7]) & 0xff)
0936: + (((long) (src[pos + 6] & 0xff)) << 8)
0937: + (((long) (src[pos + 5] & 0xff)) << 16)
0938: + (((long) (src[pos + 4] & 0xff)) << 24)
0939: + (((long) (src[pos + 3] & 0xff)) << 32)
0940: + (((long) (src[pos + 2] & 0xff)) << 40)
0941: + (((long) (src[pos + 1] & 0xff)) << 48)
0942: + (((long) (src[pos] & 0xff)) << 56);
0943: return TclDouble
0944: .newInstance(Double.longBitsToDouble(value));
0945: }
0946: }
0947: return null;
0948: }
0949:
0950: /**
0951: * Called whenever a format specifier was detected
0952: * but there are not enough arguments specified.
0953: *
0954: * @param interp - The TclInterp which called the cmdProc method.
0955: */
0956:
0957: private static void missingArg(Interp interp) // Current interpreter.
0958: throws TclException // A standard Tcl exception.
0959: {
0960: throw new TclException(interp,
0961: "not enough arguments for all format specifiers");
0962: }
0963:
0964: /**
0965: * Called whenever an invalid format specifier was detected.
0966: *
0967: * @param interp - The TclInterp which called the cmdProc method.
0968: * @param cmd - The invalid field specifier.
0969: */
0970:
0971: private static void badField(Interp interp, // Current interpreter.
0972: char cmd) // the invalid field specifier.
0973: throws TclException // A standard Tcl exception.
0974: {
0975: throw new TclException(interp, "bad field specifier \"" + cmd
0976: + "\"");
0977: }
0978:
0979: /**
0980: * Called whenever a letter aleph character (@) was detected
0981: * but there was no count specified.
0982: *
0983: * @param interp - The TclInterp which called the cmdProc method.
0984: */
0985:
0986: private static void alephWithoutCount(Interp interp) // Current interpreter.
0987: throws TclException // A standard Tcl exception.
0988: {
0989: throw new TclException(interp,
0990: "missing count for \"@\" field specifier");
0991: }
0992:
0993: /**
0994: * Called whenever a format was found which restricts the valid range
0995: * of characters in the specified string, but the string contains
0996: * at least one char not in this range.
0997: *
0998: * @param interp - The TclInterp which called the cmdProc method.
0999: */
1000:
1001: private static void expectedButGot(Interp interp, // Current interpreter.
1002: String expected, // Classification of what was expected.
1003: String str) // Was was found instead.
1004: throws TclException // A standard Tcl exception.
1005: {
1006: throw new TclException(interp, "expected " + expected
1007: + " string but got \"" + str + "\" instead");
1008: }
1009:
1010: } // end BinaryCmd
|