0001: /*
0002: * $Id: FlashBuffer.java,v 1.4 2002/07/15 02:15:03 skavish Exp $
0003: *
0004: * ===========================================================================
0005: *
0006: * The JGenerator Software License, Version 1.0
0007: *
0008: * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
0009: *
0010: * Redistribution and use in source and binary forms, with or without
0011: * modification, are permitted provided that the following conditions are met:
0012: *
0013: * 1. Redistributions of source code must retain the above copyright
0014: * notice, this list of conditions and the following disclaimer.
0015: *
0016: * 2. Redistributions in binary form must reproduce the above copyright
0017: * notice, this list of conditions and the following disclaimer in
0018: * the documentation and/or other materials provided with the
0019: * distribution.
0020: *
0021: * 3. The end-user documentation included with the redistribution, if
0022: * any, must include the following acknowlegement:
0023: * "This product includes software developed by Dmitry Skavish
0024: * (skavish@usa.net, http://www.flashgap.com/)."
0025: * Alternately, this acknowlegement may appear in the software itself,
0026: * if and wherever such third-party acknowlegements normally appear.
0027: *
0028: * 4. The name "The JGenerator" must not be used to endorse or promote
0029: * products derived from this software without prior written permission.
0030: * For written permission, please contact skavish@usa.net.
0031: *
0032: * 5. Products derived from this software may not be called "The JGenerator"
0033: * nor may "The JGenerator" appear in their names without prior written
0034: * permission of Dmitry Skavish.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
0040: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: *
0049: */
0050:
0051: package org.openlaszlo.iv.flash.util;
0052:
0053: import java.awt.geom.AffineTransform;
0054: import java.awt.geom.Rectangle2D;
0055: import java.io.*;
0056: import org.openlaszlo.iv.flash.api.*;
0057:
0058: /**
0059: * Wrapper of array of bytes.
0060: * <p>
0061: * Provides reading and writing of flash related data types.
0062: *
0063: * @author Dmitry Skavish
0064: * @see FlashOutput
0065: */
0066: public class FlashBuffer {
0067:
0068: // bit buffer and position
0069: private int bitBuf;
0070: private int bitPos;
0071:
0072: // byte array
0073: private byte buf[];
0074:
0075: // current position in the buffer for reading and writing
0076: public int pos;
0077:
0078: // size of the buffer
0079: private int size;
0080:
0081: public FlashBuffer() {
0082: }
0083:
0084: /**
0085: * Allocates buffer of given capacity.<p>
0086: * Sets current position and size to zero.
0087: *
0088: * @param capacity capacity of allocated buffer in bytes
0089: */
0090: public FlashBuffer(int capacity) {
0091: this (new byte[capacity], 0, 0);
0092: }
0093:
0094: /**
0095: * Creates buffer from given one.<p>
0096: * Sets current position to zero and size to the size of the buffer.
0097: *
0098: * @param buf buffer to init from
0099: */
0100: public FlashBuffer(byte[] buf) {
0101: this (buf, 0, buf.length);
0102: }
0103:
0104: /**
0105: * Creates buffer from given one of specified size.<p>
0106: * Sets current position to zero and size to given value.
0107: *
0108: * @param buf buffer to init from
0109: * @param size size of buffer
0110: */
0111: public FlashBuffer(byte[] buf, int size) {
0112: this (buf, 0, size);
0113: }
0114:
0115: /**
0116: * Creates buffer from given one of specified size and position.
0117: *
0118: * @param buf buffer to init from
0119: * @param pos current position
0120: * @param size size of filled buffer (writer pos)
0121: */
0122: public FlashBuffer(byte[] buf, int pos, int size) {
0123: init(buf, pos, size);
0124: }
0125:
0126: /**
0127: * Creates FlashBuffer from input stream.<p>
0128: * Reads InputStream into the buffer, sets current position
0129: * to zero and size to the size of data read.
0130: *
0131: * @author Andrew Wason
0132: * @author Dmitry Skavish
0133: * @param is InputStream to read from
0134: * @exception IOException
0135: */
0136: public FlashBuffer(InputStream is) throws IOException {
0137: size = 0;
0138: try {
0139: int count = is.available();
0140: if (count <= 0)
0141: count = 4096;
0142: buf = new byte[count + 8]; // make it a little bit bigger to avoid reallocation
0143: for (;;) {
0144: count = is.read(buf, size, buf.length - size);
0145: if (count == -1)
0146: break;
0147: size += count;
0148: if (size == buf.length)
0149: ensureCapacity(buf.length + 4096 * 4);
0150: }
0151: } finally {
0152: is.close();
0153: }
0154: pos = 0;
0155: bitBuf = 0;
0156: bitPos = 0;
0157: }
0158:
0159: public void init(byte[] buf, int pos, int size) {
0160: this .buf = buf;
0161: this .pos = pos;
0162: this .size = size;
0163: this .bitBuf = 0;
0164: this .bitPos = 0;
0165: }
0166:
0167: /**
0168: * Ensures that the buffer is as big as specified number of bytes
0169: *
0170: * @param cap required size of buffer
0171: */
0172: public final void ensureCapacity(int cap) {
0173: if (cap > buf.length) {
0174: int max = buf.length * 2;
0175: if (cap > max)
0176: max = cap + 16;
0177: if (max < 4096)
0178: max = 4096;
0179: byte[] newBuf = new byte[max];
0180: System.arraycopy(buf, 0, newBuf, 0, buf.length);
0181: buf = newBuf;
0182: }
0183: }
0184:
0185: /**
0186: * Creates copy of the buffer.
0187: *
0188: * @return copy of the buffer
0189: */
0190: public FlashBuffer getCopy() {
0191: byte[] myBuf = new byte[buf.length];
0192: System.arraycopy(buf, 0, myBuf, 0, buf.length);
0193: return new FlashBuffer(myBuf, pos, size);
0194: }
0195:
0196: /**
0197: * Current read/write position.
0198: *
0199: * @return current read/write position
0200: */
0201: public final int getPos() {
0202: return pos;
0203: }
0204:
0205: /**
0206: * Returns size of the buffer.
0207: *
0208: * @return size of the buffer
0209: */
0210: public final int getSize() {
0211: return size;
0212: }
0213:
0214: /**
0215: * Sets current read/write position.<P>
0216: * Does not increase the buffer if new position is larger
0217: * than current capacity.
0218: *
0219: * @param pos new position
0220: * @see #ensureCapacity
0221: */
0222: public final void setPos(int pos) {
0223: this .pos = pos;
0224: if (pos > size)
0225: size = pos;
0226: }
0227:
0228: /**
0229: * Increment current position.<p>
0230: * Does not increase the buffer if new position is larger
0231: * than current capacity.
0232: *
0233: * @see #ensureCapacity
0234: * @see #setPos
0235: */
0236: public final void incPos() {
0237: if (++pos > size)
0238: size = pos;
0239: }
0240:
0241: /**
0242: * Sets new size of the buffer.<p>
0243: * Does not increase the buffer if new position is larger
0244: * than current capacity.
0245: *
0246: * @param size new size of the buffer
0247: */
0248: public final void setSize(int size) {
0249: this .size = size;
0250: }
0251:
0252: /**
0253: * Skips bytes (changes current position).<P>
0254: * Does not increase the buffer if new position is larger
0255: * than current capacity.
0256: *
0257: * @param inc advance value
0258: */
0259: public final void skip(int inc) {
0260: setPos(pos + inc);
0261: }
0262:
0263: /**
0264: * Returns the whole buffer.
0265: *
0266: * @return buffer
0267: */
0268: public final byte[] getBuf() {
0269: return buf;
0270: }
0271:
0272: /*-----------------------------------------------------------------------
0273: * W R I T E R
0274: *-----------------------------------------------------------------------*/
0275:
0276: /**
0277: * Writes byte at specified position.<p>
0278: * Does not change current position.
0279: *
0280: * @param b byte to write
0281: * @param pos position to write
0282: */
0283: public final void writeByteAt(int b, int pos) {
0284: buf[pos] = (byte) b;
0285: }
0286:
0287: /**
0288: * Writes word at specified position.<p>
0289: * Does not change current position.
0290: *
0291: * @param b word to write
0292: * @param pos position to write
0293: */
0294: public final void writeWordAt(int b, int pos) {
0295: buf[pos] = (byte) b;
0296: buf[pos + 1] = (byte) (b >> 8);
0297: }
0298:
0299: /**
0300: * Writes dword at specified position.<p>
0301: * Does not change current position.
0302: *
0303: * @param b dword to write
0304: * @param pos position to write
0305: */
0306: public final void writeDWordAt(int b, int pos) {
0307: buf[pos] = (byte) b;
0308: buf[pos + 1] = (byte) (b >> 8);
0309: buf[pos + 2] = (byte) (b >> 16);
0310: buf[pos + 3] = (byte) (b >> 24);
0311: }
0312:
0313: /**
0314: * Writes byte and advance current position.
0315: *
0316: * @param b byte to write
0317: */
0318: public final void writeByte(int b) {
0319: ensureCapacity(pos + 1);
0320: buf[pos] = (byte) b;
0321: incPos();
0322: }
0323:
0324: /**
0325: * Writes word and advance current position.
0326: *
0327: * @param b word to write
0328: */
0329: public final void writeWord(int b) {
0330: ensureCapacity(pos + 2);
0331: buf[pos] = (byte) b;
0332: buf[pos + 1] = (byte) (b >> 8);
0333: setPos(pos + 2);
0334: }
0335:
0336: /**
0337: * Writes dword and advance current position.
0338: *
0339: * @param b dword to write
0340: */
0341: public final void writeDWord(int b) {
0342: ensureCapacity(pos + 4);
0343: buf[pos] = (byte) b;
0344: buf[pos + 1] = (byte) (b >> 8);
0345: buf[pos + 2] = (byte) (b >> 16);
0346: buf[pos + 3] = (byte) (b >> 24);
0347: setPos(pos + 4);
0348: }
0349:
0350: /****************************************************************
0351: * Fast operations do not call ensureCapacity
0352: */
0353:
0354: /**
0355: * Writes byte and advance current position.
0356: *
0357: * @param b byte to write
0358: */
0359: public final void _writeByte(int b) {
0360: buf[pos++] = (byte) b;
0361: }
0362:
0363: /**
0364: * Writes word and advance current position.
0365: *
0366: * @param b word to write
0367: */
0368: public final void _writeWord(int b) {
0369: buf[pos++] = (byte) b;
0370: buf[pos++] = (byte) (b >> 8);
0371: }
0372:
0373: /**
0374: * Writes dword and advance current position.
0375: *
0376: * @param b dword to write
0377: */
0378: public final void _writeDWord(int b) {
0379: buf[pos++] = (byte) b;
0380: buf[pos++] = (byte) (b >> 8);
0381: buf[pos++] = (byte) (b >> 16);
0382: buf[pos++] = (byte) (b >> 24);
0383: }
0384:
0385: /**
0386: * Writes zero-ending string into the buffer and advance current position.
0387: * (Flash5 back compatibility, uses Cp1252 encoding)
0388: * @param s string to write
0389: */
0390: public final byte[] _writeStringZ(String s) {
0391: return _writeStringZ(s, "Cp1252");
0392: }
0393:
0394: /**
0395: * Writes zero-ending string into the buffer and advance current position.
0396: *
0397: * @param s string to write
0398: * @return the string converted to a byte array in Flash's favorite encoding
0399: */
0400: public final byte[] _writeStringZ(String s, String encoding) {
0401: byte chars[];
0402: try {
0403: chars = s.getBytes(encoding);
0404: } catch (UnsupportedEncodingException e) {
0405: throw new RuntimeException("could not convert string to "
0406: + encoding);
0407: }
0408: System.arraycopy(chars, 0, buf, pos, chars.length);
0409: setPos(pos + chars.length);
0410: buf[pos++] = 0; // null-terminate the string
0411: return chars;
0412: }
0413:
0414: /**
0415: * Writes array into this one and advance current position.
0416: *
0417: * @param b intput buffer
0418: * @param off offset in the input buffer
0419: * @param len number of bytes in input buffer
0420: */
0421: public final void _writeArray(byte b[], int off, int len) {
0422: System.arraycopy(b, off, buf, pos, len);
0423: setPos(pos + len);
0424: }
0425:
0426: /****************************************************************/
0427:
0428: /**
0429: * Writes FlashBuffer into this one and advance current position.
0430: *
0431: * @param fob buffer to write
0432: */
0433: public final void writeFOB(FlashBuffer fob) {
0434: int len = fob.getSize();
0435: ensureCapacity(pos + len);
0436: System.arraycopy(fob.getBuf(), 0, buf, pos, len);
0437: setPos(pos + len);
0438: }
0439:
0440: /**
0441: * Writes array into this one and advance current position.
0442: *
0443: * @param b intput buffer
0444: * @param off offset in the input buffer
0445: * @param len number of bytes in input buffer
0446: */
0447: public final void writeArray(byte b[], int off, int len) {
0448: ensureCapacity(pos + len);
0449: System.arraycopy(b, off, buf, pos, len);
0450: setPos(pos + len);
0451: }
0452:
0453: /**
0454: * Writes zero-ending string into the buffer and advance current position.
0455: *
0456: * +++ Back compatible with Jgen-1.4/Flash5
0457: * Uses default encoding of JGen 1.4, "Cp1252".
0458: * @param s string to write
0459: *
0460: */
0461:
0462: public final byte[] writeStringZ(String s) {
0463: return writeStringZ(s, "Cp1252");
0464: }
0465:
0466: /**
0467: * Writes zero-ending string into the buffer and advance current position.
0468: *
0469: * @param s string to write
0470: * @param encoding charset encoding to use
0471: *
0472: */
0473:
0474: public final byte[] writeStringZ(String s, String encoding) {
0475: byte chars[];
0476: try {
0477: // encode utf-8 for flash 6
0478: chars = s.getBytes(encoding);
0479: } catch (UnsupportedEncodingException e) {
0480: throw new RuntimeException("could not convert string to "
0481: + encoding);
0482: }
0483: ensureCapacity(pos + chars.length + 1);
0484: for (int i = 0; i < chars.length; i++) {
0485: buf[pos++] = chars[i];
0486: }
0487: buf[pos] = 0;
0488: incPos();
0489: return chars;
0490: }
0491:
0492: /**
0493: * Writes length-prefixed string into the buffer and advance current position.
0494: *
0495: * @param s string to write
0496: */
0497: public final void writeStringL(String s) {
0498: writeStringL(s, "Cp1252");
0499: }
0500:
0501: /**
0502: * Writes length-prefixed string into the buffer and advance current position.
0503: *
0504: * @param s string to write
0505: * @param encoding charset encoding to use
0506: */
0507: public final void writeStringL(String s, String encoding) {
0508:
0509: byte chars[];
0510: try {
0511: chars = s.getBytes(encoding);
0512: } catch (UnsupportedEncodingException e) {
0513: throw new RuntimeException("could not convert string to "
0514: + encoding);
0515: }
0516: ensureCapacity(pos + chars.length + 1);
0517: buf[pos++] = (byte) chars.length;
0518: for (int i = 0; i < chars.length; i++) {
0519: buf[pos++] = chars[i];
0520: }
0521: setPos(pos); // to update size
0522: }
0523:
0524: /**
0525: * Writes flash tag into the buffer and advance current position.<P>
0526: * Depending on tag length writes short or long tag
0527: *
0528: * @param tagCode tag code
0529: * @param tagSize tag size
0530: * @see Tag
0531: * @see #writeLongTag
0532: * @see #writeLongTagAt
0533: * @see #writeShortTagAt
0534: */
0535: public final void writeTag(int tagCode, int tagSize) {
0536: if (tagSize >= 0x3f) {
0537: writeLongTag(tagCode, tagSize);
0538: } else {
0539: writeWord((tagCode << 6) | tagSize);
0540: }
0541: }
0542:
0543: /**
0544: * Writes long flash tag into the buffer and advance current position.<P>
0545: *
0546: * @param tagCode tag code
0547: * @param tagSize tag size
0548: * @see Tag
0549: * @see #writeTag
0550: * @see #writeLongTagAt
0551: * @see #writeShortTagAt
0552: */
0553: public final void writeLongTag(int tagCode, int tagSize) {
0554: writeWord((tagCode << 6) | 0x3f);
0555: writeDWord(tagSize);
0556: }
0557:
0558: /**
0559: * Writes short flash tag into the buffer at specified position.<P>
0560: * Does not advance position
0561: *
0562: * @param tagCode tag code
0563: * @param tagSize tag size
0564: * @see Tag
0565: * @see #writeLongTag
0566: * @see #writeLongTagAt
0567: * @see #writeTag
0568: */
0569: public final void writeShortTagAt(int tagCode, int tagSize, int pos) {
0570: writeWordAt((tagCode << 6) | tagSize, pos);
0571: }
0572:
0573: /**
0574: * Writes long flash tag into the buffer at specified position.<P>
0575: * Does not advance position
0576: *
0577: * @param tagCode tag code
0578: * @param tagSize tag size
0579: * @see Tag
0580: * @see #writeLongTag
0581: * @see #writeShortTagAt
0582: * @see #writeTag
0583: */
0584: public final void writeLongTagAt(int tagCode, int tagSize, int pos) {
0585: writeWordAt((tagCode << 6) | 0x3f, pos);
0586: writeDWordAt(tagSize, pos + 2);
0587: }
0588:
0589: /**
0590: * Writes lower bit to bit buffer.
0591: *
0592: * @param b bit to write
0593: * @see #initBits
0594: * @see #flushBits
0595: * @see #writeBits
0596: */
0597: public final void writeBit(int b) {
0598: writeBits(b, 1);
0599: }
0600:
0601: /**
0602: * Writes boolean as a bit to bit buffer.
0603: *
0604: * @param b boolean to write
0605: * @see #initBits
0606: * @see #flushBits
0607: */
0608: public final void writeBool(boolean b) {
0609: writeBits(b ? 1 : 0, 1);
0610: }
0611:
0612: /**
0613: * Writes bits into the buffer.<P>
0614: * Before starting writing bits you have to init or flush bits
0615: * buffer using methods {@link #initBits} or {@link #flushBits}
0616: *
0617: * @param v bits to write packed in integer
0618: * @param len number of bits to write
0619: * @see #initBits
0620: * @see #flushBits
0621: */
0622: public final void writeBits(int v, int len) {
0623: ensureCapacity(pos + 4);
0624: for (;;) {
0625: v = v & ((1 << len) - 1);
0626: int l = 8 - bitPos;
0627: int s = l - len;
0628: if (s >= 0) {
0629: bitBuf = (bitBuf << len) | v;
0630: bitPos += len;
0631: return;
0632: } else {
0633: s = -s;
0634: int bb = (bitBuf << l) | (v >>> s);
0635: buf[pos] = (byte) bb;
0636: incPos();
0637: len = s;
0638: bitBuf = 0;
0639: bitPos = 0;
0640: }
0641: }
0642: }
0643:
0644: /**
0645: * Flushes bits buffer into flash buffer.<P>
0646: * Has to be called after you finished writing series of bits
0647: *
0648: * @see #writeBits
0649: * @see #initBits
0650: */
0651: public final void flushBits() {
0652: if (bitPos != 0) {
0653: int bb = bitBuf << (8 - bitPos);
0654: writeByte(bb);
0655: }
0656: bitBuf = 0;
0657: bitPos = 0;
0658: }
0659:
0660: /**
0661: * Inits bits buffer.<P>
0662: * Has to be called before writing series of bits or
0663: * before reading bits
0664: *
0665: * @see #writeBits
0666: * @see #flushBits
0667: * @see #skipBits
0668: * @see #getBits
0669: */
0670: public final void initBits() {
0671: bitBuf = 0;
0672: bitPos = 0;
0673: }
0674:
0675: /**
0676: * Writes specified inputstream to this buffer
0677: *
0678: * @param is input stream
0679: */
0680: public final void write(InputStream is) throws IOException {
0681: try {
0682: int count = is.available();
0683: if (count <= 0)
0684: count = 4096;
0685: ensureCapacity(pos + count + 8);
0686: for (;;) {
0687: count = is.read(buf, pos, buf.length - pos);
0688: if (count == -1)
0689: break;
0690: pos += count;
0691: if (pos == buf.length)
0692: ensureCapacity(buf.length + 4096 * 4);
0693: }
0694: setPos(pos);
0695: } finally {
0696: is.close();
0697: }
0698: }
0699:
0700: /*-----------------------------------------------------------------------
0701: * R E A D E R
0702: *-----------------------------------------------------------------------*/
0703:
0704: /**
0705: * Skips bits.
0706: *
0707: * @param n number of bits to skip
0708: * @see #initBits
0709: */
0710: public final void skipBits(int n) {
0711: for (;;) {
0712: int s = n - bitPos;
0713: if (s > 0) {
0714: n -= bitPos;
0715: // get the next buffer
0716: bitBuf = getUByte();
0717: bitPos = 8;
0718: } else {
0719: // Consume a portion of the buffer
0720: s = -s;
0721: bitPos = s;
0722: bitBuf &= (1 << s) - 1; // mask off the consumed bits
0723: break;
0724: }
0725: }
0726: }
0727:
0728: /**
0729: * Reads <b>unsigned</b> bits from the buffer.<P>
0730: *
0731: * According to profiler this is probably the most
0732: * time consuming operation. Below there is a new version,
0733: * but I did not test it much, it's about 30% percent faster.
0734: *
0735: * @param n number of bits to read
0736: * @return read bits
0737: * @see #initBits
0738: * @see #getSBits
0739: */
0740: public final int getBits(int n) {
0741: // get n bits from the stream.
0742: int v = 0;
0743:
0744: for (;;) {
0745: int s = n - bitPos;
0746: if (s > 0) {
0747: // Consume the entire buffer
0748: v |= bitBuf << s;
0749: n -= bitPos;
0750:
0751: // get the next buffer
0752: bitBuf = getUByte();
0753: bitPos = 8;
0754: } else {
0755: // Consume a portion of the buffer
0756: s = -s;
0757: v |= bitBuf >> s;
0758: bitPos = s;
0759: bitBuf &= (1 << s) - 1; // mask off the consumed bits
0760: return v;
0761: }
0762: }
0763: }
0764:
0765: // new version of getBits
0766: public final int new_getBits(int n) {
0767: // get n bits from the stream.
0768:
0769: int s = n - bitPos;
0770: if (s > 0) {
0771: // Consume the entire buffer
0772: int v = bitBuf << s;
0773: n -= bitPos;
0774:
0775: // get the next buffer
0776: if (n <= 8) {
0777: bitBuf = getUByte();
0778: bitPos = 8;
0779: } else if (n <= 16) {
0780: bitBuf = (getUByte() << 8) | getUByte();
0781: bitPos = 16;
0782: } else if (n <= 24) {
0783: bitBuf = (getUByte() << 16) | (getUByte() << 8)
0784: | getUByte();
0785: bitPos = 24;
0786: } else {
0787: bitBuf = (getUByte() << 24) | (getUByte() << 16)
0788: | (getUByte() << 8) | getUByte();
0789: bitPos = 32;
0790: }
0791: bitPos -= n;
0792: v |= bitBuf >> bitPos;
0793: bitBuf &= (1 << bitPos) - 1;
0794: return v;
0795: }
0796:
0797: // Consume a portion of the buffer
0798: s = -s;
0799: int v = bitBuf >> s;
0800: bitPos = s;
0801: bitBuf &= (1 << s) - 1; // mask off the consumed bits
0802: return v;
0803: }
0804:
0805: /**
0806: * Reads <b>signed</b> bits from the buffer.<P>
0807: *
0808: * @param n number of bits to read
0809: * @return read bits extended with sign
0810: * @see #initBits
0811: * @see #getBits
0812: */
0813: public final int getSBits(int n) {
0814: // get n bits from the string with sign extension.
0815: // get the number as an unsigned value.
0816: int v = getBits(n);
0817:
0818: // Is the number negative?
0819: if ((v & (1 << (n - 1))) != 0) {
0820: // Yes. Extend the sign.
0821: v |= -1 << n;
0822: }
0823:
0824: return v;
0825: }
0826:
0827: /**
0828: * Reads one bit and returns it as boolean
0829: *
0830: * @return true - if bit is 1, false - if bit is 0
0831: */
0832: public boolean getBool() {
0833: return getBits(1) == 1;
0834: }
0835:
0836: /**
0837: * Reads bytes into given FlashBuffer.
0838: *
0839: * @param fob flash buffer where to read bytes
0840: * @param length number of bytes to read
0841: */
0842: public final void getTo(FlashBuffer fob, int length) {
0843: fob.writeArray(buf, pos, length);
0844: pos += length;
0845: }
0846:
0847: /**
0848: * Reads zero-ending string.
0849: *
0850: * @return read string
0851: */
0852: public final String getString() {
0853: int sp = pos;
0854: while (buf[pos++] != 0)
0855: ;
0856: return new String(buf, sp, pos - sp - 1);
0857: }
0858:
0859: /**
0860: * Read string by its length.
0861: *
0862: * @param length string length
0863: * @return read string
0864: */
0865: public final String getString(int length) {
0866: int sp = pos;
0867: pos += length;
0868: return new String(buf, sp, length);
0869: }
0870:
0871: /**
0872: * Reads bytes into array of bytes.
0873: *
0874: * @param length number of bytes to read
0875: * @return created array of bytes with data
0876: */
0877: public final byte[] getBytes(int length) {
0878: byte[] ba = new byte[length];
0879: System.arraycopy(buf, pos, ba, 0, length);
0880: pos += length;
0881: return ba;
0882: }
0883:
0884: /**
0885: * Reads one signed byte.
0886: *
0887: * @return signed byte
0888: */
0889: public final int getByte() {
0890: return buf[pos++];
0891: }
0892:
0893: /**
0894: * Reads one unsigned byte.
0895: *
0896: * @return unsigned byte
0897: */
0898: public final int getUByte() {
0899: return buf[pos++] & 0xff;
0900: }
0901:
0902: public final int getByteAt(int p) {
0903: return buf[p];
0904: }
0905:
0906: public final int getUByteAt(int p) {
0907: return buf[p] & 0xff;
0908: }
0909:
0910: /**
0911: * Reads one signed word.
0912: *
0913: * @return signed word
0914: */
0915: public final int getWord() {
0916: int r = Util.getWord(buf[pos], buf[pos + 1]);
0917: pos += 2;
0918: return r;
0919: }
0920:
0921: public final int getWordAt(int p) {
0922: return Util.getWord(buf[p], buf[p + 1]);
0923: }
0924:
0925: /**
0926: * Reads one unsigned word.
0927: *
0928: * @return unsigned word
0929: */
0930: public final int getUWord() {
0931: int r = Util.getUWord(buf[pos], buf[pos + 1]);
0932: pos += 2;
0933: return r;
0934: }
0935:
0936: public final int getUWordAt(int p) {
0937: return Util.getUWord(buf[p], buf[p + 1]);
0938: }
0939:
0940: /**
0941: * Reads one signed dword.
0942: *
0943: * @return signed dword
0944: */
0945: public int getDWord() {
0946: int r = Util.getDWord(buf[pos], buf[pos + 1], buf[pos + 2],
0947: buf[pos + 3]);
0948: pos += 4;
0949: return r;
0950: }
0951:
0952: public int getDWordAt(int p) {
0953: return Util
0954: .getDWord(buf[p], buf[p + 1], buf[p + 2], buf[p + 3]);
0955: }
0956:
0957: /**
0958: * Reads one unsigned dword.
0959: *
0960: * @return unsigned dword
0961: */
0962: public int getUDWord() {
0963: int r = Util.getUDWord(buf[pos], buf[pos + 1], buf[pos + 2],
0964: buf[pos + 3]);
0965: pos += 4;
0966: return r;
0967: }
0968:
0969: public int getUDWordAt(int p) {
0970: return Util.getUDWord(buf[p], buf[p + 1], buf[p + 2],
0971: buf[p + 3]);
0972: }
0973:
0974: /*-----------------------------------------------------------------------
0975: * InputStream
0976: *-----------------------------------------------------------------------*/
0977:
0978: /**
0979: * Creates input stream which can be used to read data from this buffer.
0980: *
0981: * @return input stream
0982: * @see #getOutputStream
0983: */
0984: public InputStream getInputStream() {
0985: return new FlashBufferInputStream();
0986: }
0987:
0988: /**
0989: * Creates input stream which can be used to read data from this buffer.
0990: *
0991: * @param pos first input position, position to start reading from
0992: * @return input stream
0993: * @see #getOutputStream
0994: */
0995: public InputStream getInputStream(int pos) {
0996: return new FlashBufferInputStream(pos);
0997: }
0998:
0999: public class FlashBufferInputStream extends InputStream {
1000:
1001: private int curPos = 0;
1002:
1003: public FlashBufferInputStream() {
1004: }
1005:
1006: public FlashBufferInputStream(int curPos) {
1007: this .curPos = curPos;
1008: }
1009:
1010: public int read() throws IOException {
1011: if (curPos >= size)
1012: return -1;
1013: return buf[curPos++] & 0xff;
1014: }
1015:
1016: public int read(byte b[], int off, int len) throws IOException {
1017: if (len == 0)
1018: return 0;
1019: int sz = Math.min(len, size - curPos);
1020: if (sz <= 0)
1021: return -1;
1022: System.arraycopy(buf, curPos, b, off, sz);
1023: curPos += sz;
1024: return sz;
1025: }
1026:
1027: public int available() throws IOException {
1028: return size - curPos;
1029: }
1030: }
1031:
1032: /*-----------------------------------------------------------------------
1033: * OutputStream
1034: *-----------------------------------------------------------------------*/
1035:
1036: /**
1037: * Creates output stream which can be used to write data to this buffer.
1038: *
1039: * @return output stream
1040: * @see #getInputStream
1041: */
1042: public OutputStream getOutputStream() {
1043: return new FlashBufferOutputStream();
1044: }
1045:
1046: public class FlashBufferOutputStream extends OutputStream {
1047:
1048: public FlashBufferOutputStream() {
1049: }
1050:
1051: public void write(int b) {
1052: writeByte(b);
1053: }
1054:
1055: public void write(byte b[], int off, int len) {
1056: writeArray(b, off, len);
1057: }
1058: }
1059:
1060: /*-----------------------------------------------------------------------
1061: * AffineTransform
1062: *-----------------------------------------------------------------------*/
1063:
1064: public AffineTransform getMatrix() {
1065: initBits();
1066:
1067: double m00; // scale x
1068: double m10; // skew0 (y shear)
1069: double m01; // skew1 (x shear)
1070: double m11; // scale y
1071: double m02; // translate x
1072: double m12; // trasnlate y
1073:
1074: // Scale terms
1075: if (getBool()) {
1076: int nBits = getBits(5);
1077: m00 = Util.fixed2double(getSBits(nBits));
1078: m11 = Util.fixed2double(getSBits(nBits));
1079: } else {
1080: m00 = 1.0;
1081: m11 = 1.0;
1082: }
1083:
1084: // Rotate/skew terms
1085: if (getBool()) {
1086: int nBits = getBits(5);
1087: m10 = Util.fixed2double(getSBits(nBits));
1088: m01 = Util.fixed2double(getSBits(nBits));
1089: } else {
1090: m10 = 0.0;
1091: m01 = 0.0;
1092: }
1093:
1094: // Translate terms
1095: int nBits = getBits(5);
1096: m02 = getSBits(nBits);
1097: m12 = getSBits(nBits);
1098:
1099: AffineTransform m = new AffineTransform(m00, m10, m01, m11,
1100: m02, m12);
1101: return m;
1102: }
1103:
1104: /**
1105: * Skips MATRIX tag without creating Matrix object
1106: */
1107: public void skipMatrix() {
1108: initBits();
1109: // Scale terms
1110: if (getBool()) {
1111: int nBits = getBits(5);
1112: skipBits(nBits + nBits);
1113: }
1114: // Rotate/skew terms
1115: if (getBool()) {
1116: int nBits = getBits(5);
1117: skipBits(nBits + nBits);
1118: }
1119: // Translate terms
1120: int nBits = getBits(5);
1121: skipBits(nBits + nBits);
1122: }
1123:
1124: public void write(AffineTransform m) {
1125: initBits();
1126:
1127: double m00 = m.getScaleX();
1128: double m10 = m.getShearY();
1129: double m01 = m.getShearX();
1130: double m11 = m.getScaleY();
1131: double m02 = m.getTranslateX();
1132: double m12 = m.getTranslateY();
1133:
1134: if (m00 != 1.0 || m11 != 1.0) {
1135: writeBit(1);
1136: int i_scaleX = Util.double2fixed(m00);
1137: int i_scaleY = Util.double2fixed(m11);
1138: int nBits = Util.getMinBitsS(Util
1139: .getMax(i_scaleX, i_scaleY));
1140: writeBits(nBits, 5);
1141: writeBits(i_scaleX, nBits);
1142: writeBits(i_scaleY, nBits);
1143: } else {
1144: writeBit(0);
1145: }
1146:
1147: if (m10 != 0.0 || m01 != 0.0) {
1148: writeBit(1);
1149: int i_rotateSkew0 = Util.double2fixed(m10);
1150: int i_rotateSkew1 = Util.double2fixed(m01);
1151: int nBits = Util.getMinBitsS(Util.getMax(i_rotateSkew0,
1152: i_rotateSkew1));
1153: writeBits(nBits, 5);
1154: writeBits(i_rotateSkew0, nBits);
1155: writeBits(i_rotateSkew1, nBits);
1156: } else {
1157: writeBit(0);
1158: }
1159:
1160: int i_translateX = (int) m02;
1161: int i_translateY = (int) m12;
1162: int nBits = Util.getMinBitsS(Util.getMax(i_translateX,
1163: i_translateY));
1164: writeBits(nBits, 5);
1165: writeBits(i_translateX, nBits);
1166: writeBits(i_translateY, nBits);
1167: flushBits();
1168: }
1169:
1170: /*-----------------------------------------------------------------------
1171: * Rectangle2D
1172: *-----------------------------------------------------------------------*/
1173:
1174: public Rectangle2D getRect() {
1175: initBits();
1176: int nBits = getBits(5);
1177: int xmin = getSBits(nBits);
1178: int xmax = getSBits(nBits);
1179: int ymin = getSBits(nBits);
1180: int ymax = getSBits(nBits);
1181:
1182: Rectangle2D r = GeomHelper.newRectangle(xmin, ymin,
1183: xmax - xmin, ymax - ymin);
1184: return r;
1185: }
1186:
1187: /**
1188: * Skips rectangle
1189: */
1190: public void skipRect() {
1191: initBits();
1192: int nBits = getBits(5);
1193: skip(((5 + (nBits * 4)) + 7) / 8 - 1);
1194: }
1195:
1196: public void write(Rectangle2D r) {
1197: initBits();
1198:
1199: int xmin = (int) r.getMinX();
1200: int xmax = (int) r.getMaxX();
1201: int ymin = (int) r.getMinY();
1202: int ymax = (int) r.getMaxY();
1203:
1204: int nBits = Util.getMinBitsS(Util
1205: .getMax(xmin, xmax, ymin, ymax));
1206: writeBits(nBits, 5);
1207: writeBits(xmin, nBits);
1208: writeBits(xmax, nBits);
1209: writeBits(ymin, nBits);
1210: writeBits(ymax, nBits);
1211: flushBits();
1212: }
1213:
1214: public String toString() {
1215: return new String(buf, 0, pos);
1216: }
1217:
1218: public String toString(String encoding)
1219: throws java.io.UnsupportedEncodingException {
1220: return new String(buf, 0, pos, encoding);
1221: }
1222: }
|