Source Code Cross Referenced for Blob.java in  » ERP-CRM-Financial » sakai » org » sakaiproject » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » sakai » org.sakaiproject.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**********************************************************************************
0002:         * $URL: https://source.sakaiproject.org/svn/util/tags/sakai_2-4-1/util-util/util/src/java/org/sakaiproject/util/Blob.java $
0003:         * $Id: Blob.java 6832 2006-03-21 20:43:34Z ggolden@umich.edu $
0004:         ***********************************************************************************
0005:         *
0006:         * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007:         * 
0008:         * Licensed under the Educational Community License, Version 1.0 (the "License"); 
0009:         * you may not use this file except in compliance with the License. 
0010:         * You may obtain a copy of the License at
0011:         * 
0012:         *      http://www.opensource.org/licenses/ecl1.php
0013:         * 
0014:         * Unless required by applicable law or agreed to in writing, software 
0015:         * distributed under the License is distributed on an "AS IS" BASIS, 
0016:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
0017:         * See the License for the specific language governing permissions and 
0018:         * limitations under the License.
0019:         *
0020:         **********************************************************************************/package org.sakaiproject.util;
0021:
0022:        import java.io.EOFException;
0023:        import java.io.IOException;
0024:        import java.io.InputStream;
0025:        import java.io.ObjectInputStream;
0026:        import java.io.ObjectOutputStream;
0027:        import java.io.OutputStream;
0028:        import java.io.PrintStream;
0029:        import java.io.Serializable;
0030:        import java.util.Enumeration;
0031:        import java.util.NoSuchElementException;
0032:
0033:        /**
0034:         * A blob is a Binary Large OBject.
0035:         * The Blob uses a linked list structure internally so it is
0036:         * not susceptible to running out of memory when growing.  This can
0037:         * be a problem with very large Vectors -- when they grow, a new, larger
0038:         * internal array is created and elements copied over.  Thus, for that
0039:         * short amount of time, there are two copies of the array.  That, plus
0040:         * the added overhead of storing bytes in object form, make the Blob the
0041:         * preferrable method for storing raw data.
0042:         * <P>Since it uses ints as indicies, a single Blob
0043:         * can hold up to Integer.MAX_VALUE (2,147,483,647) bytes.
0044:         * Could be modified to use longs and then could hold up to
0045:         * Long.MAX_VALUE (9.2233e18) bytes if your computer had that much storage.  :^)
0046:         * <P>This is my 'pet' class.
0047:         * @author T. Gee
0048:         *
0049:         */
0050:        public class Blob implements  Cloneable, Serializable {
0051:
0052:            /**
0053:             * 
0054:             */
0055:            private static final long serialVersionUID = 3832623997476484914L;
0056:
0057:            /**
0058:             * The default internal data storage node size.
0059:             */
0060:            public static final int NODE_SIZE = 512;
0061:
0062:            // THE FOLLOWING THREE FIELDS ARE TRANSIENT BECAUSE WE DO THE
0063:            // SERIALIZATION OURSELVES.  WE DO THIS BECAUSE OF JAVA'S
0064:            // LIMITED STACK SIZE FOR SERIALIZATION.
0065:
0066:            // The head of the linked list of data nodes.
0067:            protected transient BlobNode head;
0068:
0069:            // The current tail of the linked list of data nodes.
0070:            protected transient BlobNode tail;
0071:
0072:            // The current size of the Blob.
0073:            // It is possible to compute this, but it is stored
0074:            // for convience.
0075:            protected transient int size;
0076:
0077:            // The actual internal data storage node size.
0078:            protected int nodeSize;
0079:
0080:            // Current Node -- set when seek() is called
0081:            protected transient BlobNode curr;
0082:
0083:            // For the internal enumeration methods
0084:            protected transient BlobNode enumerationNode = null;
0085:            protected transient int enumerationPos = 0;
0086:
0087:            /**
0088:             * An inclusive between function (for chars).
0089:             * @param test The char to test.
0090:             * @param low The lower bound.
0091:             * @param high The upper bound.
0092:             * @return true if test is between low and high (inclusive),
0093:             * false otherwise.
0094:             *
0095:             */
0096:            protected static final boolean between(char test, char low,
0097:                    char high) {
0098:                return ((test >= low) && (test <= high));
0099:            }
0100:
0101:            /**
0102:             * An inclusive between function (for ints).
0103:             * @param test The number to test.
0104:             * @param low The lower bound.
0105:             * @param high The upper bound.
0106:             * @return true if test is between low and high (inclusive),
0107:             * false otherwise.
0108:             *
0109:             */
0110:            public static final boolean between(int test, int low, int high) {
0111:                return ((test >= low) && (test <= high));
0112:            }
0113:
0114:            /**
0115:             * Returns a hex representation of a byte.
0116:             * @param b The byte to convert to hex.
0117:             * @return The 2-digit hex value of the supplied byte.
0118:             *
0119:             */
0120:            public static final String toHex(byte b) {
0121:
0122:                char ret[] = new char[2];
0123:
0124:                ret[0] = hexDigit((b >>> 4) & (byte) 0x0F);
0125:                ret[1] = hexDigit((b >>> 0) & (byte) 0x0F);
0126:
0127:                return new String(ret);
0128:            }
0129:
0130:            /**
0131:             * Returns the hex representation of a short.
0132:             * @param s The short to convert to hex.
0133:             * @return The 4-digit hex value of the supplied short.
0134:             *
0135:             */
0136:            public static final String toHex(short s) {
0137:
0138:                StringBuffer sb = new StringBuffer(5);
0139:
0140:                sb.append(toHex((byte) (s >>> 8)));
0141:                sb.append(' ');
0142:                sb.append(toHex((byte) (s >>> 0)));
0143:
0144:                return sb.toString();
0145:            }
0146:
0147:            /**
0148:             * Returns the hex representation of an int.
0149:             * @param i The int to convert to hex.
0150:             * @return The 8-digit hex value of the supplied int.
0151:             *
0152:             */
0153:            public static final String toHex(int i) {
0154:
0155:                StringBuffer sb = new StringBuffer(11);
0156:
0157:                sb.append(toHex((byte) (i >>> 24)));
0158:                sb.append(' ');
0159:                sb.append(toHex((byte) (i >>> 16)));
0160:                sb.append(' ');
0161:                sb.append(toHex((byte) (i >>> 8)));
0162:                sb.append(' ');
0163:                sb.append(toHex((byte) (i >>> 0)));
0164:
0165:                return sb.toString();
0166:            }
0167:
0168:            /**
0169:             * Returns the hex representation of an long.
0170:             * @param l The long to convert to hex.
0171:             * @return The 16-digit hex value of the supplied long.
0172:             *
0173:             */
0174:            public static final String toHex(long l) {
0175:
0176:                StringBuffer sb = new StringBuffer(11);
0177:
0178:                sb.append(toHex((byte) (l >>> 56)));
0179:                sb.append(' ');
0180:                sb.append(toHex((byte) (l >>> 48)));
0181:                sb.append(' ');
0182:                sb.append(toHex((byte) (l >>> 40)));
0183:                sb.append(' ');
0184:                sb.append(toHex((byte) (l >>> 32)));
0185:                sb.append(' ');
0186:                sb.append(toHex((byte) (l >>> 24)));
0187:                sb.append(' ');
0188:                sb.append(toHex((byte) (l >>> 16)));
0189:                sb.append(' ');
0190:                sb.append(toHex((byte) (l >>> 8)));
0191:                sb.append(' ');
0192:                sb.append(toHex((byte) (l >>> 0)));
0193:
0194:                return sb.toString();
0195:            }
0196:
0197:            /**
0198:             * Returns the hex representation of the characters of a String.
0199:             * @param s The String to convert to hex.
0200:             * @return A String where each character of the original string
0201:             * is given as a space seperated sequence of hex values.
0202:             *
0203:             */
0204:            public static final String toHex(String s) {
0205:
0206:                StringBuffer sb = new StringBuffer();
0207:
0208:                char chars[] = s.toCharArray();
0209:                for (int x = 0; x < chars.length; x++) {
0210:                    sb.append(toHex((byte) chars[x]));
0211:                    if (x != (chars.length - 1)) {
0212:                        sb.append(' ');
0213:                    }
0214:                }
0215:
0216:                return sb.toString();
0217:
0218:            }
0219:
0220:            /**
0221:             * Returns the hex digit cooresponding to a number between 0 and 15.
0222:             * @param i The number to get the hex digit for.
0223:             * @return The hex digit cooresponding to that number.
0224:             * @exception java.lang.IllegalArgumentException If supplied digit
0225:             * is not between 0 and 15 inclusive.
0226:             *
0227:             */
0228:            public static final char hexDigit(int i) {
0229:
0230:                switch (i) {
0231:                case 0:
0232:                    return '0';
0233:                case 1:
0234:                    return '1';
0235:                case 2:
0236:                    return '2';
0237:                case 3:
0238:                    return '3';
0239:                case 4:
0240:                    return '4';
0241:                case 5:
0242:                    return '5';
0243:                case 6:
0244:                    return '6';
0245:                case 7:
0246:                    return '7';
0247:                case 8:
0248:                    return '8';
0249:                case 9:
0250:                    return '9';
0251:                case 10:
0252:                    return 'A';
0253:                case 11:
0254:                    return 'B';
0255:                case 12:
0256:                    return 'C';
0257:                case 13:
0258:                    return 'D';
0259:                case 14:
0260:                    return 'E';
0261:                case 15:
0262:                    return 'F';
0263:                }
0264:
0265:                throw new IllegalArgumentException("Invalid digit:" + i);
0266:            }
0267:
0268:            /**
0269:             * Returns a string of a specified number of a specified character.
0270:             * @param n The number of characters to create in the return String.
0271:             * @param c The character to create.
0272:             * @return A String of the requested number of the requested character.
0273:             *
0274:             */
0275:            public static final String strstr(int n, char c) {
0276:
0277:                StringBuffer ret = new StringBuffer(n);
0278:
0279:                for (int x = 0; x < n; x++) {
0280:                    ret.append(c);
0281:                }
0282:
0283:                return ret.toString();
0284:            }
0285:
0286:            /**
0287:             * Returns a string of a specified number of spaces.
0288:             * @param n The number of spaces to create.
0289:             * @return A String of the requested number of spaces.
0290:             * @see #strstr
0291:             *
0292:             */
0293:            public static final String spaces(int n) {
0294:                return strstr(n, ' ');
0295:            }
0296:
0297:            ////////////////////////////////////////////////////////////
0298:            ////////////////////////////////////////////////////////////
0299:            ////////////////////////////////////////////////////////////
0300:            //
0301:            //       CONSTRUCTORS
0302:            //
0303:
0304:            /**
0305:             * Creates a new, empty Blob.
0306:             * Uses default internal node size.
0307:             *
0308:             */
0309:            public Blob() {
0310:                this (NODE_SIZE);
0311:            }
0312:
0313:            /**
0314:             * Creates a new, empty Blob and specifies the default internal
0315:             * node size.
0316:             * @param growSize The number of bytes to allocate for a new node
0317:             * in the internal data storage structure.
0318:             *
0319:             */
0320:            public Blob(int nodeSize) {
0321:                this .nodeSize = nodeSize;
0322:
0323:                // Create a new, empty head node
0324:                head = new BlobNode(nodeSize);
0325:                tail = head;
0326:
0327:                size = 0;
0328:            }
0329:
0330:            /**
0331:             * Creates a new blob that is a copy of an existing blob.
0332:             * @param b The Blob to copy.
0333:             *
0334:             */
0335:            public Blob(Blob b) {
0336:                this ();
0337:
0338:                append(b);
0339:            }
0340:
0341:            /**
0342:             * Creates a new blob and initialized it with a byte array.
0343:             * @param arr A byte array to copy entirely into the new Blob.
0344:             *
0345:             */
0346:            public Blob(byte arr[]) {
0347:                this (arr, 0, arr.length);
0348:            }
0349:
0350:            /**
0351:             * Creates a new blob and initialized it with a byte array.
0352:             * @param arr A byte array to copy into the new Blob.
0353:             * @param startPos The location to start extracting bytes from.
0354:             * @param len The length of the array to copy in.
0355:             *
0356:             */
0357:            public Blob(byte arr[], int startPos, int len) {
0358:                this ();
0359:
0360:                append(arr, startPos, len);
0361:            }
0362:
0363:            ////////////////////////////////////////////////////////////
0364:            ////////////////////////////////////////////////////////////
0365:            ////////////////////////////////////////////////////////////
0366:            //
0367:            //       EXTERNAL METHODS
0368:            //
0369:
0370:            //
0371:            // Append Methods
0372:            //
0373:
0374:            /**
0375:             * Appends a byte to the end of the Blob.
0376:             * @param b The byte to add.
0377:             *
0378:             */
0379:            public synchronized void append(byte b) {
0380:
0381:                // Ensure the capacity of the current tail node
0382:                if (tail.freespace() == 0) {
0383:                    appendNode(nodeSize);
0384:                }
0385:
0386:                // Add the byte to the end node
0387:                tail.data[tail.size] = b;
0388:                tail.size++;
0389:
0390:                // incriment our total.
0391:                size++;
0392:            }
0393:
0394:            /**
0395:             * Appends one byte (in the form of a char) to the end of the Blob.
0396:             * Strips the high byte off.
0397:             * @param c The character to add.
0398:             *
0399:             */
0400:            public synchronized void append(char c) {
0401:                append(false, c);
0402:            }
0403:
0404:            /**
0405:             * Appends one or two bytes (in the form of a char) to the end
0406:             * of the Blob.
0407:             * Can optionally add the high byte or not.
0408:             * @param addHighByte 'true' to add the character's high byte to the
0409:             * Blob; 'false' to strip it.
0410:             * @param c The character to add.
0411:             *
0412:             */
0413:            public synchronized void append(boolean addHighByte, char c) {
0414:
0415:                if (addHighByte) {
0416:                    // Byte 1
0417:                    append((byte) (c >> 8));
0418:                }
0419:
0420:                // Byte 2
0421:                append((byte) (c >> 0));
0422:            }
0423:
0424:            /**
0425:             * Appends two bytes (in the form of a short) to the end of the Blob.
0426:             * @param s The short integer to add.
0427:             *
0428:             */
0429:            public synchronized void append(short s) {
0430:
0431:                // Byte 1
0432:                append((byte) (s >> 8));
0433:
0434:                // Byte 2
0435:                append((byte) (s >> 0));
0436:            }
0437:
0438:            /**
0439:             * Appends four bytes (in the form of an int) to the end of the Blob.
0440:             * @param i The integer to add.
0441:             *
0442:             */
0443:            public synchronized void append(int i) {
0444:
0445:                // Byte 1
0446:                append((byte) (i >> 24));
0447:
0448:                // Byte 2
0449:                append((byte) (i >> 16));
0450:
0451:                // Byte 3
0452:                append((byte) (i >> 8));
0453:
0454:                // Byte 4
0455:                append((byte) (i >> 0));
0456:            }
0457:
0458:            /**
0459:             * Appends eight bytes (in the form of a long) to the end of the Blob.
0460:             * @param l The long integer to add.
0461:             *
0462:             */
0463:            public synchronized void append(long l) {
0464:
0465:                // Byte 1
0466:                append((byte) (l >> 56));
0467:
0468:                // Byte 2
0469:                append((byte) (l >> 48));
0470:
0471:                // Byte 3
0472:                append((byte) (l >> 40));
0473:
0474:                // Byte 4
0475:                append((byte) (l >> 32));
0476:
0477:                // Byte 5
0478:                append((byte) (l >> 24));
0479:
0480:                // Byte 6
0481:                append((byte) (l >> 16));
0482:
0483:                // Byte 7
0484:                append((byte) (l >> 8));
0485:
0486:                // Byte 8
0487:                append((byte) (l >> 0));
0488:            }
0489:
0490:            /**
0491:             * Appends four bytes (in the form of a float) to the end of the Blob.
0492:             * @param f The float to add.
0493:             *
0494:             */
0495:            public synchronized void append(float f) {
0496:
0497:                // Append the integer created from the bytes of this float
0498:                append(Float.floatToIntBits(f));
0499:            }
0500:
0501:            /**
0502:             * Appends eight bytes (in the form of a double) to the end of the Blob.
0503:             * @param d The double to add.
0504:             *
0505:             */
0506:            public synchronized void append(double d) {
0507:
0508:                // Append the long created from the bytes of this double
0509:                append(Double.doubleToLongBits(d));
0510:            }
0511:
0512:            /**
0513:             * Appends bytes from a String to the end of the Blob.
0514:             * Strips the high bytes from the characters.
0515:             * @param s The String to add.
0516:             *
0517:             */
0518:            public synchronized void append(String s) {
0519:                append(false, s);
0520:            }
0521:
0522:            /**
0523:             * Appends bytes from a String to the end of the Blob.
0524:             * Can optionally add the high bytes from the characters or not.
0525:             * @param addHighByte 'true' to add the characters' high byte to the
0526:             * Blob; 'false' to strip it.
0527:             * @param s The String to add.
0528:             *
0529:             */
0530:            public synchronized void append(boolean addHighByte, String s) {
0531:
0532:                for (int x = 0; x < s.length(); x++) {
0533:                    append(addHighByte, s.charAt(x));
0534:                }
0535:            }
0536:
0537:            /**
0538:             * Appends an entire byte array to the end of the Blob.
0539:             * @param arr The array to add bytes from.
0540:             *
0541:             */
0542:            public synchronized void append(byte arr[]) {
0543:                append(arr, 0, arr.length);
0544:            }
0545:
0546:            /**
0547:             * Appends a byte array to the end of the Blob.
0548:             * @param arr The array to add bytes from.
0549:             * @param startPos The position to start the byte extraction
0550:             * from the array at.
0551:             * @param len The number of bytes to read from the array.
0552:             *
0553:             */
0554:            public synchronized void append(byte arr[], int startPos, int len) {
0555:
0556:                // If the current tail node has enuff storage for this
0557:                // new addition, use it, otherwise, append a new node.
0558:                if (tail.freespace() < len) {
0559:                    BlobNode oldTail = tail;
0560:                    appendNode(Math.max(len, nodeSize));
0561:
0562:                    // If old tail node was empty, we'll eliminate it
0563:                    if (oldTail.size == 0) {
0564:                        BlobNode bn = findBefore(oldTail);
0565:                        if (bn == null) {
0566:                            // oldTail == head
0567:                            head = tail;
0568:                        } else {
0569:                            bn.next = tail;
0570:                        }
0571:                    } // endif
0572:
0573:                } // endif
0574:
0575:                System.arraycopy(arr, startPos, tail.data, tail.size, len);
0576:                tail.size += len;
0577:
0578:                size += len;
0579:
0580:            } // end append()
0581:
0582:            /**
0583:             * Appends the bytes from a Blob to the end of the Blob.
0584:             * @param b The Blob to draw bytes from.
0585:             *
0586:             */
0587:            public synchronized void append(Blob b) {
0588:
0589:                BlobNode bn;
0590:                boolean setHead = false;
0591:
0592:                // We're going to clone the target Blob's nodes and
0593:                // tack them on the end.
0594:
0595:                // if our current node is empty, we'll back up one before appending
0596:                if (tail.size == 0) {
0597:                    bn = findBefore(tail);
0598:                    if (bn == null) {
0599:                        // tail == head
0600:                        setHead = true;
0601:                    } else {
0602:                        tail = bn;
0603:                        tail.next = null;
0604:                    }
0605:                }
0606:
0607:                // Now append all of the target's nodes
0608:                bn = b.head;
0609:
0610:                if (setHead) {
0611:                    // set the head node
0612:                    // (the head node now is empty)
0613:                    head = (BlobNode) bn.clone();
0614:                    tail = head;
0615:                    size = head.size;
0616:
0617:                    // we'll start with the next node down the line
0618:                    // (since we just used the first one)
0619:                    bn = bn.next;
0620:                }
0621:
0622:                while (bn != null) {
0623:                    tail.next = (BlobNode) bn.clone();
0624:                    tail = tail.next;
0625:                    size += tail.size;
0626:
0627:                    bn = bn.next;
0628:                }
0629:
0630:            } // end append()
0631:
0632:            //
0633:            // Data insert Methods
0634:            //
0635:
0636:            /**
0637:             * Inserts a byte into the blob at the position pos.
0638:             * Everything else is moved back.
0639:             * @param pos The postition to add the byte at (0 -> beginning).
0640:             * @param b The byte to add.
0641:             * @see Blob#insertBytes
0642:             * @exception java.lang.IndexOutOfBoundsException If pos is
0643:             * outside range of Blob.
0644:             *
0645:             */
0646:            public synchronized void insertByte(int pos, byte b) {
0647:
0648:                byte arr[] = new byte[1];
0649:                arr[0] = b;
0650:                insertBytes(pos, arr, 0, 1);
0651:
0652:            } // end insertByte()
0653:
0654:            /**
0655:             * Inserts a byte into the blob at the position pos.
0656:             * Everything else is moved back.
0657:             * @param pos The postition to begin adding the bytes at (0 -> beginning).
0658:             * @param arr The array of bytes to add from.
0659:             * @exception java.lang.IndexOutOfBoundsException If pos is
0660:             * outside range of Blob.
0661:             *
0662:             */
0663:            public synchronized void insertBytes(int pos, byte arr[]) {
0664:                this .insertBytes(pos, arr, 0, arr.length);
0665:            }
0666:
0667:            /**
0668:             * Inserts a byte into the blob at the position pos.
0669:             * Everything else is moved back.
0670:             * @param pos The postition to begin adding the bytes at (0 -> beginning).
0671:             * @param arr The array of bytes to add from.
0672:             * @param startPos The position to begin byte copy from.
0673:             * @param len The number of bytes to add from the array.
0674:             * @exception java.lang.IndexOutOfBoundsException If pos is
0675:             * outside range of Blob.
0676:             *
0677:             */
0678:            public synchronized void insertBytes(int pos, byte arr[],
0679:                    int startPos, int len) {
0680:
0681:                // are we just appending?
0682:                if (pos == size) {
0683:                    append(arr, startPos, len);
0684:                    return;
0685:                }
0686:
0687:                // Is the position valid?
0688:                if (!between(pos, 0, (size - 1))) {
0689:                    throw new IndexOutOfBoundsException();
0690:                } // endif
0691:
0692:                // Find the correct node and index into that node
0693:                int currIndex = seek(pos);
0694:
0695:                // Do we have enough space in the current node for the
0696:                // new information
0697:                if (curr.freespace() >= len) {
0698:                    // Insert the info into the current node
0699:
0700:                    // Move the old stuff back
0701:                    System.arraycopy(curr.data, currIndex, curr.data,
0702:                            (currIndex + len), (curr.size - currIndex));
0703:
0704:                    // Copy in the new stuff
0705:                    System.arraycopy(arr, startPos, curr.data, currIndex, len);
0706:
0707:                    // Set the new size
0708:                    this .curr.size += len;
0709:
0710:                } else {
0711:                    // not enough room in the inn.
0712:                    // erect a barn, errr, a new node for it.
0713:                    BlobNode newNode = new BlobNode(nodeSize, arr, startPos,
0714:                            len);
0715:                    BlobNode before = findBefore(curr);
0716:
0717:                    // Where do we stick it?
0718:                    if (currIndex == 0) {
0719:                        // put it before the current node
0720:                        if (before == null) {
0721:                            // inserting before head
0722:                            newNode.next = head;
0723:                            head = newNode;
0724:                        } else {
0725:                            // inserting in middle
0726:                            newNode.next = before.next;
0727:                            before.next = newNode;
0728:                        }
0729:                    } else {
0730:                        // We'll have to split the current node
0731:                        BlobNode a = new BlobNode(Math.max(nodeSize, currIndex));
0732:                        BlobNode b = new BlobNode(Math.max(nodeSize,
0733:                                (curr.size - currIndex)));
0734:
0735:                        // Copy the data
0736:                        a.size = currIndex;
0737:                        System.arraycopy(curr.data, 0, a.data, 0, a.size);
0738:                        b.size = curr.size - currIndex;
0739:                        System.arraycopy(curr.data, currIndex, b.data, 0,
0740:                                b.size);
0741:
0742:                        // Set up the links.
0743:                        b.next = (before == null) ? head : before.next;
0744:                        newNode.next = b;
0745:                        a.next = newNode;
0746:                        if (before == null) {
0747:                            head = a;
0748:                        } else {
0749:                            before.next = a;
0750:                        }
0751:                    } // endif
0752:
0753:                } // endif
0754:
0755:                // adjust size
0756:                size += len;
0757:
0758:            } // end insertBytes()
0759:
0760:            //
0761:            // Data remove methods
0762:            //
0763:
0764:            /**
0765:             * Truncates the Blob to the specified position.
0766:             * The Blob will have the given number of bytes left.
0767:             * @param len The size to truncate the Blob to.
0768:             * @exception java.lang.IndexOutOfBoundsException If len is
0769:             * outside range of Blob.
0770:             *
0771:             */
0772:            public synchronized void truncate(int len) {
0773:
0774:                // Anything to do?
0775:                if (len == size) {
0776:                    return;
0777:                }
0778:
0779:                // Is the data within bounds?
0780:                if (!between(len, 0, size)) {
0781:                    throw new IndexOutOfBoundsException();
0782:                }
0783:
0784:                // find the correct node and truncate that node
0785:                // to the required number of bytes to make the
0786:                // whole thing work.
0787:                // We have to do the seek() and truncate() on different
0788:                // lines as seek() sets 'curr'..
0789:                int currIndex = seek(len);
0790:                curr.size = currIndex;
0791:
0792:                // Set the new size;
0793:                size = len;
0794:
0795:                // set the next pointer of this node to null
0796:                curr.next = null;
0797:                tail = curr;
0798:
0799:            } // end truncate()
0800:
0801:            /**
0802:             * Removes a byte from the Blob at the requested position.
0803:             * Everything else is moved up.
0804:             * @param pos The position to remove a byte from (0 -> beginning).
0805:             * @see Blob#removeBytes
0806:             * @exception java.lang.IndexOutOfBoundsException If pos is
0807:             * outside range of Blob.
0808:             *
0809:             */
0810:            public synchronized void removeByte(int pos) {
0811:                removeBytes(pos, 1);
0812:            } // end removeByte()
0813:
0814:            /**
0815:             * Removes a number of bytes from the Blob at the requested position.
0816:             * Everything else is moved up.
0817:             * @param pos The position to remove the bytes from (0 -> beginning).
0818:             * @param len The number of bytes to remove.
0819:             * @exception java.lang.IndexOutOfBoundsException If pos and len are
0820:             * outside range of Blob.
0821:             *
0822:             */
0823:            public synchronized void removeBytes(int pos, int len) {
0824:
0825:                // Is the data within bounds?
0826:                if (!(between(pos, 0, (size - 1)) && between((pos + len), 0,
0827:                        size))) {
0828:
0829:                    throw new IndexOutOfBoundsException();
0830:                }
0831:
0832:                BlobNode startNode, endNode;
0833:                int startPos, endPos;
0834:
0835:                // Get the starting and ending locations
0836:                startPos = seek(pos);
0837:                startNode = curr;
0838:
0839:                endPos = seek(pos + len);
0840:                endNode = curr;
0841:
0842:                if (startNode == endNode) {
0843:                    // Just removing stuff from one node
0844:
0845:                    // move the stuff up and adjust length
0846:                    System.arraycopy(curr.data, endPos, curr.data, startPos,
0847:                            (curr.size - endPos));
0848:                    curr.size -= len;
0849:
0850:                } else {
0851:                    // Removing stuff across several nodes
0852:                    // Create a new node to hold the info
0853:                    BlobNode newNode = new BlobNode(Math.max(nodeSize,
0854:                            (startPos + (endNode.size - endPos))));
0855:
0856:                    // Move stuff into this new node
0857:                    System.arraycopy(startNode.data, 0, newNode.data, 0,
0858:                            startPos);
0859:
0860:                    System.arraycopy(endNode.data, endPos, newNode.data,
0861:                            startPos, (endNode.size - endPos));
0862:
0863:                    newNode.size = (startPos + 1) + (endNode.size - endPos);
0864:
0865:                    // update the pointers
0866:                    newNode.next = endNode.next;
0867:
0868:                    // Find the node PREVIOUS to the startNode
0869:                    BlobNode before = findBefore(startNode);
0870:                    if (before == null) {
0871:                        head = newNode;
0872:                    } else {
0873:                        before.next = newNode;
0874:                    }
0875:                } // endif
0876:
0877:                // Set the new size
0878:                size -= len;
0879:
0880:            } // end removeBytes()
0881:
0882:            //
0883:            // Data Retrieval methods
0884:            //
0885:
0886:            /**
0887:             * Gets the bytes of the blob as a byte array.
0888:             * @return An array of the bytes that compose the Blob.
0889:             *
0890:             */
0891:            public byte[] getBytes() {
0892:                return getBytes(0, size);
0893:            }
0894:
0895:            /**
0896:             * Returns a subset of the bytes of the blob as a byte array.
0897:             * @param start start index to begin draw (included in get).
0898:             * @param len number of bytes to extract.
0899:             * @return An array of the bytes that compose the Blob.
0900:             * @exception java.lang.IndexOutOfBoundsException If start and len are
0901:             * outside range of Blob.
0902:             *
0903:             */
0904:            public synchronized byte[] getBytes(int start, int len) {
0905:
0906:                // Special case
0907:                if ((start == 0) && (len == 0)) {
0908:                    return new byte[0];
0909:                }
0910:
0911:                // Is the data within bounds?
0912:                if (!(between(start, 0, (size - 1)) && between((start + len),
0913:                        0, size))) {
0914:                    throw new IndexOutOfBoundsException();
0915:                }
0916:
0917:                byte ret[] = new byte[len];
0918:                int bytesCopied = 0;
0919:                int copyFromThis = 0;
0920:
0921:                int currIndex = seek(start);
0922:                while (bytesCopied < len) {
0923:                    copyFromThis = Math.min((curr.size - currIndex),
0924:                            (len - bytesCopied));
0925:
0926:                    System.arraycopy(curr.data, currIndex, ret, bytesCopied,
0927:                            copyFromThis);
0928:                    bytesCopied += copyFromThis;
0929:
0930:                    curr = curr.next;
0931:                    currIndex = 0;
0932:                } // endwhile
0933:
0934:                return ret;
0935:
0936:            } // end getBytes()
0937:
0938:            /**
0939:             * Returns the byte at a specific location.
0940:             * @param pos The position to from which to return the byte
0941:             * (0 -> beginning).
0942:             * @return The byte at requested position.
0943:             * @exception java.lang.IndexOutOfBoundsException If pos is
0944:             * outside range of Blob.
0945:             *
0946:             */
0947:            public synchronized byte byteAt(int pos) {
0948:
0949:                // Is the data within bounds?
0950:                if (!between(pos, 0, (size - 1))) {
0951:                    throw new IndexOutOfBoundsException();
0952:                }
0953:
0954:                // Find the correct node and index into that node
0955:                int currIndex = seek(pos);
0956:
0957:                // Get the byte
0958:                return curr.data[currIndex];
0959:            }
0960:
0961:            /**
0962:             * Returns a character reconstructed from one byte at a specific location.
0963:             * Sets the high byte in the character to 0x0.
0964:             * @param pos The position to get the byte to reconstuct the character
0965:             * (0 -> beginning).
0966:             * @return The reconstructed character.
0967:             * @exception java.lang.IndexOutOfBoundsException If the requested
0968:             * char is outside the Blob.
0969:             *
0970:             */
0971:            public synchronized char charAt(int pos) {
0972:                return charAt(false, pos);
0973:            } // end charAt()
0974:
0975:            /**
0976:             * Returns a character reconstructed from one or two bytes at a
0977:             * specific location.
0978:             * @param useHighByte 'true' to use two bytes (one for the high byte)
0979:             * to reconstruct a character; 'false' to use one byte and set the
0980:             * high byte to 0x0.
0981:             * @param pos The position to get the byte(s) to reconstuct the character
0982:             * (0 -> beginning).
0983:             * @return The reconstructed character.
0984:             * @exception java.lang.IndexOutOfBoundsException If the requested
0985:             * bytes are outside the Blob.
0986:             *
0987:             */
0988:            public synchronized char charAt(boolean useHighByte, int pos) {
0989:
0990:                // Is the data within bounds?
0991:                if (!between(pos, 0, (size - (useHighByte ? 2 : 1)))) {
0992:                    throw new IndexOutOfBoundsException();
0993:                }
0994:
0995:                // Return character
0996:                char ret;
0997:
0998:                if (useHighByte) {
0999:                    // get a short and cast it as a char.
1000:                    ret = (char) shortAt(pos);
1001:
1002:                } else {
1003:                    // get a byte and cast it as a char.
1004:                    ret = (char) byteAt(pos);
1005:
1006:                } // endif
1007:
1008:                return ret;
1009:            } // end charAt()
1010:
1011:            /**
1012:             * Returns a short int reconstructed from two bytes at a specific
1013:             * location.
1014:             * @param pos The position to get the bytes to reconstuct the short
1015:             * (0 -> beginning).
1016:             * @return The reconstructed short.
1017:             * @exception java.lang.IndexOutOfBoundsException If the requested
1018:             * bytes are outside the Blob.
1019:             *
1020:             */
1021:            public synchronized short shortAt(int pos) {
1022:
1023:                // Is the data within bounds?
1024:                if (!between(pos, 0, (size - 2))) {
1025:                    throw new IndexOutOfBoundsException();
1026:                }
1027:
1028:                // Return value
1029:                short ret = 0x0, temp;
1030:
1031:                // Find proper location
1032:                beginEnumeration(pos);
1033:
1034:                for (int x = 0; x < 2; x++) {
1035:
1036:                    // get next byte
1037:                    // We shift the input byte up all the way to the high
1038:                    // byte and then back down to the req'd position because
1039:                    // java won't let us cast an a byte as a larger integer
1040:                    // type without propigating the sign bit thruout the
1041:                    // higher bytes.  This ain't what we need so we jump
1042:                    // thru some hoops to avoid it.
1043:                    temp = (short) ((nextByte() << (1 * 8)) >>> (1 * 8));
1044:                    ret |= (temp << (8 * (1 - x)));
1045:
1046:                } // endfor
1047:
1048:                return ret;
1049:            } // end shortAt()
1050:
1051:            /**
1052:             * Returns an int reconstructed from four bytes at a specific
1053:             * location.
1054:             * @param pos The position to get the bytes to reconstuct the int
1055:             * (0 -> beginning).
1056:             * @return The reconstructed int.
1057:             * @exception java.lang.IndexOutOfBoundsException If the requested
1058:             * bytes are outside the Blob.
1059:             *
1060:             */
1061:            public synchronized int intAt(int pos) {
1062:
1063:                // Is the data within bounds?
1064:                if (!between(pos, 0, (size - 4))) {
1065:                    throw new IndexOutOfBoundsException();
1066:                }
1067:
1068:                // Return value
1069:                int ret = 0x0, temp;
1070:
1071:                // Find proper location
1072:                beginEnumeration(pos);
1073:
1074:                for (int x = 0; x < 4; x++) {
1075:
1076:                    // get next byte
1077:                    // We shift the input byte up all the way to the high
1078:                    // byte and then back down to the req'd position because
1079:                    // java won't let us cast an a byte as a larger integer
1080:                    // type without propigating the sign bit thruout the
1081:                    // higher bytes.  This ain't what we need so we jump
1082:                    // thru some hoops to avoid it.
1083:                    temp = ((int) nextByte() << (3 * 8)) >>> (3 * 8);
1084:                    ret |= (temp << (8 * (3 - x)));
1085:
1086:                } // endfor
1087:
1088:                return ret;
1089:            } // end intAt()
1090:
1091:            /**
1092:             * Returns a long int reconstructed from eight bytes at a specific
1093:             * location.
1094:             * @param pos The position to get the bytes to reconstuct the long
1095:             * (0 -> beginning).
1096:             * @return The reconstructed long.
1097:             * @exception java.lang.IndexOutOfBoundsException If the requested
1098:             * bytes are outside the Blob.
1099:             *
1100:             */
1101:            public synchronized long longAt(int pos) {
1102:
1103:                // Is the data within bounds?
1104:                if (!between(pos, 0, (size - 8))) {
1105:                    throw new IndexOutOfBoundsException();
1106:                }
1107:
1108:                // Return value
1109:                long ret = 0x0, temp;
1110:
1111:                // Find proper location
1112:                beginEnumeration(pos);
1113:
1114:                for (int x = 0; x < 8; x++) {
1115:
1116:                    // get next byte
1117:                    // We shift the input byte up all the way to the high
1118:                    // byte and then back down to the req'd position because
1119:                    // java won't let us cast an a byte as a larger integer
1120:                    // type without propigating the sign bit thruout the
1121:                    // higher bytes.  This ain't what we need so we jump
1122:                    // thru some hoops to avoid it.
1123:                    temp = ((long) nextByte() << (7 * 8)) >>> (7 * 8);
1124:                    ret |= (temp << (8 * (7 - x)));
1125:
1126:                } // endfor
1127:
1128:                return ret;
1129:            } // end longAt()
1130:
1131:            /**
1132:             * Returns a floating point number reconstructed from four bytes
1133:             * at a specific
1134:             * location.
1135:             * @param pos The position to get the bytes to reconstuct the float
1136:             * (0 -> beginning).
1137:             * @return The reconstructed float.
1138:             * @exception java.lang.IndexOutOfBoundsException If the requested
1139:             * bytes are outside the Blob.
1140:             *
1141:             */
1142:            protected synchronized float floatAt(int pos) {
1143:
1144:                return Float.intBitsToFloat(intAt(pos));
1145:
1146:            } // end floatAt()
1147:
1148:            /**
1149:             * Returns a double precision floating point number reconstructed
1150:             * from eight bytes at a specific
1151:             * @param pos The position to get the bytes to reconstuct the double
1152:             * (0 -> beginning).
1153:             * @return The reconstructed double.
1154:             * @exception java.lang.IndexOutOfBoundsException If the requested
1155:             * bytes are outside the Blob.
1156:             *
1157:             */
1158:            public synchronized double doubleAt(int pos) {
1159:
1160:                return Double.longBitsToDouble(longAt(pos));
1161:
1162:            } // end floatAt()
1163:
1164:            /**
1165:             * Returns a String reconstructed from the bytes of the Blob.
1166:             * Sets the high byte in each character to 0x0.
1167:             * @return The reconstructed String.
1168:             *
1169:             */
1170:            public synchronized String getString() {
1171:
1172:                return getString(false, 0, size);
1173:            } // end getString()
1174:
1175:            /**
1176:             * Returns a String reconstructed from bytes at a specific location.
1177:             * Sets the high byte in each character to 0x0.
1178:             * @param pos The position to start retrieving the bytes to reconstuct
1179:             * the String (0 -> beginning).
1180:             * @param len The length of the to-be-returned String.
1181:             * @return The reconstructed String.
1182:             * @exception java.lang.IndexOutOfBoundsException If the requested
1183:             * bytes are outside the Blob.
1184:             *
1185:             */
1186:            public synchronized String getString(int pos, int len) {
1187:                return getString(false, pos, len);
1188:            } // end getString()
1189:
1190:            /**
1191:             * Returns a String reconstructed from bytes at a specific location.
1192:             * @param useHighByte 'true' to use two bytes (one for the high byte)
1193:             * to reconstruct each character; 'false' to use one byte and set the
1194:             * high byte to 0x0.
1195:             * @param pos The position to start retrieving the bytes to reconstuct
1196:             * the String (0 -> beginning).
1197:             * @param len The length of the to-be-returned String.
1198:             * @return The reconstructed String.
1199:             * @exception java.lang.IndexOutOfBoundsException If the requested
1200:             * bytes are outside the Blob.
1201:             *
1202:             */
1203:            public synchronized String getString(boolean useHighByte, int pos,
1204:                    int len) {
1205:
1206:                // Special case
1207:                if ((pos == 0) && (len == 0)) {
1208:                    return new String();
1209:                }
1210:
1211:                // Is the data within bounds?
1212:                if (!(between(pos, 0, (size - 1)) && between(
1213:                        (pos + (len * (useHighByte ? 2 : 1))), 0, size))) {
1214:                    throw new IndexOutOfBoundsException();
1215:                }
1216:
1217:                // Return String
1218:                StringBuffer ret = new StringBuffer(len);
1219:
1220:                // hold character
1221:                char c;
1222:
1223:                // Find proper location
1224:                beginEnumeration(pos);
1225:
1226:                for (int x = 0; x < len; x++) {
1227:
1228:                    if (useHighByte) {
1229:                        // Use both bytes
1230:
1231:                        // high byte
1232:                        c = (char) (nextByte() << 8);
1233:
1234:                        // low byte
1235:                        c |= nextByte();
1236:
1237:                    } else {
1238:                        // just get one (low) byte
1239:                        c = (char) nextByte();
1240:
1241:                    } // endif
1242:
1243:                    // Add the new character
1244:                    ret.append(c);
1245:
1246:                } // endfor
1247:
1248:                return ret.toString();
1249:            } // end getString()
1250:
1251:            /**
1252:             * Clones this Blob.
1253:             * The resulting Blob will have the same data as the first.
1254:             * (altho possibly not the same internal configuration).
1255:             *
1256:             */
1257:            public synchronized Object clone() {
1258:                // We can just call our getBlob method to do this.
1259:                return getBlob(0, size);
1260:            }
1261:
1262:            /**
1263:             * Returns a new Blob drawn from bytes at a specific location.
1264:             * @param pos The position to start retrieving the bytes to build
1265:             * the new Blob (0 -> beginning).
1266:             * @param len The number of bytes to put into the new Blob.
1267:             * @return The newly constructed Blob.
1268:             * @exception java.lang.IndexOutOfBoundsException If the requested
1269:             * bytes are outside the Blob.
1270:             *
1271:             */
1272:            public synchronized Blob getBlob(int pos, int len) {
1273:                // cop out and use our other methods.  Speed be damned -- this
1274:                // isn't that important anyway.
1275:                // We *should* just go thru and clone the appropiate
1276:                // BlobNodes and just modifiy the ones on the end....
1277:                return new Blob(getBytes(pos, len));
1278:
1279:            } // end getBlob()
1280:
1281:            //
1282:            // Misc Methods
1283:            //
1284:
1285:            /**
1286:             * Returns an enumeration of the bytes in this Blob.
1287:             * The objects returned from the calls to nextElement are
1288:             * of type Byte.
1289:             * @param pos The location from which to begin enumerating bytes.
1290:             * @exception java.lang.IndexOutOfBoundsException If pos is
1291:             * outside range of Blob.
1292:             *
1293:             */
1294:            public synchronized Enumeration enumerateBytes(int pos) {
1295:
1296:                // Is the data within bounds?
1297:                if (!between(pos, 0, (size - 1))) {
1298:                    throw new IndexOutOfBoundsException();
1299:                }
1300:
1301:                final int cep = seek(pos);
1302:                final BlobNode cen = curr;
1303:
1304:                return new Enumeration() {
1305:
1306:                    int currEnumerationPos = cep;
1307:                    BlobNode currEnumerationNode = cen;
1308:
1309:                    public synchronized boolean hasMoreElements() {
1310:                        return (currEnumerationNode != null);
1311:                    }
1312:
1313:                    public synchronized Object nextElement() {
1314:                        if (currEnumerationNode == null) {
1315:                            throw new NoSuchElementException(
1316:                                    "Past end of current Enumeration");
1317:                        }
1318:
1319:                        byte ret = currEnumerationNode.data[currEnumerationPos++];
1320:
1321:                        // check to see if we're at the end of the current node
1322:                        if (currEnumerationPos == currEnumerationNode.size) {
1323:                            // At end, go to next node
1324:                            currEnumerationNode = currEnumerationNode.next;
1325:                            currEnumerationPos = 0;
1326:                        }
1327:
1328:                        // All done
1329:                        return new Byte(ret);
1330:                    } // end nextElement()
1331:
1332:                }; // end Enumeration
1333:            } // end enumerateBytes
1334:
1335:            /**
1336:             * Sets a byte at a particular position.
1337:             * @param pos The position to set the byte at.
1338:             * @param b The value to set that postion to.
1339:             * @exception java.lang.IndexOutOfBoundsException If pos is
1340:             * outside range of Blob.
1341:             *
1342:             */
1343:            public synchronized void setByteAt(int pos, byte b) {
1344:                // Is the data within bounds?
1345:                if (!between(pos, 0, (size - 1))) {
1346:                    throw new IndexOutOfBoundsException();
1347:                }
1348:
1349:                // Find the correct node and index into that node
1350:                int currIndex = seek(pos);
1351:
1352:                // Set the byte
1353:                curr.data[currIndex] = b;
1354:            }
1355:
1356:            /**
1357:             * Gets the number of bytes in the Blob.
1358:             * @return The number of bytes in the Blob.
1359:             *
1360:             */
1361:            public synchronized int length() {
1362:                return size;
1363:            }
1364:
1365:            /**
1366:             * Returns true if the blob is equal to the given object.
1367:             * True only if supplied object is a Blob and the two contain
1368:             * exactly the same data.
1369:             *
1370:             */
1371:            public synchronized boolean equals(Object o) {
1372:                if ((o == null) || !(o instanceof  Blob)) {
1373:                    return false;
1374:                }
1375:
1376:                Blob b = (Blob) o;
1377:
1378:                // Are they the same length?
1379:                if (size != b.size) {
1380:                    return false;
1381:                }
1382:
1383:                // Compare the data
1384:                beginEnumeration(0);
1385:                b.beginEnumeration(0);
1386:                while (hasMoreBytes()) {
1387:                    if (nextByte() != b.nextByte()) {
1388:                        return false;
1389:                    }
1390:                }
1391:
1392:                // If we got here, they must be equal
1393:                return true;
1394:
1395:            } // end equals()
1396:
1397:            /**
1398:             * Searches for a byte and returns an index to the first one found.
1399:             * @param b The byte to search for.
1400:             * @return The index of the first match or -1 if not found.
1401:             *
1402:             */
1403:            public synchronized int indexOf(byte b) {
1404:                return indexOf(b, 0);
1405:            }
1406:
1407:            /**
1408:             * Searches for a byte and returns an index to the first one found.
1409:             * Search starts at given index and includes that index.
1410:             * @param b The byte to search for.
1411:             * @param pos The position to begin searching at (0 -> beginning).
1412:             * @return The index of the first match or -1 if not found.
1413:             * @exception java.lang.IndexOutOfBoundsException If pos is
1414:             * outside range of Blob.
1415:             *
1416:             */
1417:            public synchronized int indexOf(byte b, int pos) {
1418:
1419:                // Is the data within bounds?
1420:                if (!between(pos, 0, (size - 1))) {
1421:                    throw new IndexOutOfBoundsException();
1422:                }
1423:
1424:                beginEnumeration(pos);
1425:                int currentPos = pos;
1426:
1427:                while (hasMoreBytes()) {
1428:
1429:                    if (nextByte() == b) {
1430:                        return currentPos;
1431:                    }
1432:
1433:                    currentPos++;
1434:                } // endwhile
1435:
1436:                return -1;
1437:            }
1438:
1439:            //
1440:            // IO Methods
1441:            //
1442:
1443:            /**
1444:             * Reads bytes from an InputStream into the Blob.
1445:             * @param len The number of bytes to attempt to read.
1446:             * @param in The InputStream to read from.
1447:             * @return The number of bytes read and appended to the blob
1448:             * or -1 if the end of the stream was reached.
1449:             * @exception java.io.IOException If there is a problem reading.
1450:             *
1451:             */
1452:            public synchronized int read(int len, InputStream in)
1453:                    throws IOException {
1454:
1455:                byte b[] = new byte[len];
1456:                int bytesRead;
1457:                try {
1458:                    bytesRead = in.read(b);
1459:                } catch (EOFException e) {
1460:                    // We'll just return a -1 just as if
1461:                    // we had gotten a -1 in response from the read
1462:                    return -1;
1463:
1464:                } catch (IOException e) {
1465:                    // Throw this one to the caller
1466:                    throw (IOException) e.fillInStackTrace();
1467:                }
1468:                append(b, 0, bytesRead);
1469:                return bytesRead;
1470:
1471:            } // end read();
1472:
1473:            /**
1474:             * Reads all bytes from an InputStream into the Blob.
1475:             * This will read an InputStream byte-by-byte until EOF and
1476:             * append the data to the end of the Blob.
1477:             * @param in The InputStream to read from.
1478:             * @return The number of bytes read and appended to the blob
1479:             * or -1 if the end of the stream was reached immediately.
1480:             * @exception java.io.IOException If there is a problem reading.
1481:             *
1482:             */
1483:            public synchronized int read(InputStream in) throws IOException {
1484:
1485:                byte b[] = new byte[nodeSize];
1486:                int bytesRead, totalBytesRead = -1;
1487:                while (true) {
1488:                    try {
1489:                        bytesRead = in.read(b);
1490:                    } catch (EOFException e) {
1491:                        // We'll just break out of the loop just as if
1492:                        // we had gotten a -1 in response from the read
1493:                        break;
1494:
1495:                    } catch (IOException e) {
1496:                        // Throw this one to the caller
1497:                        throw (IOException) e.fillInStackTrace();
1498:                    }
1499:
1500:                    // if we're at EOF, get out of the loop.
1501:                    if (bytesRead == -1) {
1502:                        break;
1503:                    }
1504:
1505:                    // We have totalBytesRead set to -1 initially
1506:                    // so that we'll return -1 if the stream is at EOF
1507:                    // right off the bat.
1508:                    // Now, we have to set it to 0 so that our byte sum
1509:                    // will be correct.
1510:                    if (totalBytesRead == -1) {
1511:                        totalBytesRead = 0;
1512:                    }
1513:
1514:                    append(b, 0, bytesRead);
1515:                    totalBytesRead += bytesRead;
1516:                }
1517:                return totalBytesRead;
1518:
1519:            } // end read();
1520:
1521:            /**
1522:             * Reads most bytes from an InputStream into the Blob -
1523:             * not to exceed <max> bytes by much (it may read up to nodeSize more).
1524:             * This will read an InputStream byte-by-byte until EOF and
1525:             * append the data to the end of the Blob.
1526:             * @param in The InputStream to read from.
1527:             * @param max the max (sort of) bytes to read
1528:             * @return The number of bytes read and appended to the blob
1529:             * or -1 if the end of the stream was reached immediately.
1530:             * or -2 if we cut off due to max before end
1531:             * @exception java.io.IOException If there is a problem reading.
1532:             *
1533:             */
1534:            public synchronized int readLimiting(InputStream in, long max)
1535:                    throws IOException {
1536:                byte b[] = new byte[nodeSize];
1537:                int bytesRead, totalBytesRead = -1;
1538:                while (true) {
1539:                    try {
1540:                        bytesRead = in.read(b);
1541:                    } catch (EOFException e) {
1542:                        // We'll just break out of the loop just as if
1543:                        // we had gotten a -1 in response from the read
1544:                        break;
1545:
1546:                    } catch (IOException e) {
1547:                        // Throw this one to the caller
1548:                        throw (IOException) e.fillInStackTrace();
1549:                    }
1550:
1551:                    // if we're at EOF, get out of the loop.
1552:                    if (bytesRead == -1) {
1553:                        break;
1554:                    }
1555:
1556:                    // We have totalBytesRead set to -1 initially
1557:                    // so that we'll return -1 if the stream is at EOF
1558:                    // right off the bat.
1559:                    // Now, we have to set it to 0 so that our byte sum
1560:                    // will be correct.
1561:                    if (totalBytesRead == -1) {
1562:                        totalBytesRead = 0;
1563:                    }
1564:
1565:                    // if we're already over the limit, get out!
1566:                    if ((totalBytesRead > max) && (bytesRead > 0)) {
1567:                        totalBytesRead = -2;
1568:                        break;
1569:                    }
1570:
1571:                    append(b, 0, bytesRead);
1572:                    totalBytesRead += bytesRead;
1573:                }
1574:                return totalBytesRead;
1575:
1576:            } // readLimiting
1577:
1578:            /**
1579:             * provide an output stream that writes to the END of the blob (appends)
1580:             */
1581:            public OutputStream outputStream() {
1582:                return new OutputStream() {
1583:                    public void write(int b) {
1584:                        append((byte) b);
1585:                    }
1586:
1587:                    public void write(byte[] b) {
1588:                        append(b);
1589:                    }
1590:
1591:                    public void write(byte[] b, int off, int len) {
1592:                        append(b, off, len);
1593:                    }
1594:                };
1595:
1596:            } // outputStream
1597:
1598:            /**
1599:             * provide an input stream that reads the blob contents
1600:             */
1601:            public InputStream inputStream() {
1602:                return new InputStream() {
1603:                    /** next byte to return */
1604:                    private int m_pos = 0;
1605:
1606:                    /*public int read(byte b[], int off, int len)
1607:                    	throws IOException
1608:                    {
1609:                    	return super.read(b, off, len);
1610:                    }*/
1611:
1612:                    public int read() throws IOException {
1613:                        int rv = -1;
1614:                        try {
1615:                            rv = byteAt(m_pos);
1616:
1617:                            // input streams must return values 0..255, but our bytes are signed
1618:                            if (rv < 0)
1619:                                rv = 256 + rv;
1620:
1621:                            m_pos++;
1622:                        } catch (IndexOutOfBoundsException e) {
1623:                        }
1624:
1625:                        return rv;
1626:                    }
1627:
1628:                    public int available() {
1629:                        return size - m_pos;
1630:                    }
1631:                };
1632:
1633:            } // inputStream
1634:
1635:            /**
1636:             * Writes the entire contents of the Blob to an OutputStream.
1637:             * @param out The OutputStream to write to.
1638:             * @exception java.io.IOException If there is a problem writing.
1639:             *
1640:             */
1641:            public synchronized void write(OutputStream out) throws IOException {
1642:                write(0, size, out);
1643:            }
1644:
1645:            /**
1646:             * Writes the contents of a part of the Blob to an OutputStream.
1647:             * @param pos The position to begin writing from.
1648:             * @param len The number of bytes to write.
1649:             * @param out The OutputStream to write to.
1650:             * @exception java.lang.IndexOutOfBoundsException If pos and len are
1651:             * outside range of Blob.
1652:             * @exception java.io.IOException If there is a problem writing.
1653:             *
1654:             */
1655:            public synchronized void write(int pos, int len, OutputStream out)
1656:                    throws IOException {
1657:
1658:                // Is the data within bounds?
1659:                if (!(between(pos, 0, (size - 1)) && between((pos + len), 0,
1660:                        size))) {
1661:                    throw new IndexOutOfBoundsException();
1662:                }
1663:
1664:                // Go to the beginning of the data
1665:                int bytesWritten = 0;
1666:                int writeFromThis = 0;
1667:
1668:                int currIndex = seek(pos);
1669:                while (bytesWritten < len) {
1670:                    writeFromThis = Math.min((curr.size - currIndex),
1671:                            (len - bytesWritten));
1672:
1673:                    // Write out the stuff,
1674:                    out.write(curr.data, currIndex, writeFromThis);
1675:                    bytesWritten += writeFromThis;
1676:
1677:                    curr = curr.next;
1678:                    currIndex = 0;
1679:                } // endwhile
1680:
1681:            } // end write();
1682:
1683:            /**
1684:             * Generates and returns an 8-byte checksum.
1685:             *
1686:             */
1687:            public synchronized long checksum() {
1688:
1689:                long ret = 0, temp = 0, hold = 0;
1690:                int index = 0;
1691:
1692:                if (size == 0) {
1693:                    return ret;
1694:                }
1695:
1696:                beginEnumeration(0);
1697:                while (hasMoreBytes()) {
1698:
1699:                    // put the byte into the low end byte of a long
1700:                    temp = ((long) nextByte() << (7 * 8)) >>> (7 * 8);
1701:
1702:                    // put the byte into a holder long
1703:                    hold |= (temp << (8 * (7 - index)));
1704:
1705:                    if (++index == 8) {
1706:                        // XOR the last eight bytes with the checksum value
1707:                        ret ^= hold;
1708:
1709:                        // reset the holder long
1710:                        hold = 0;
1711:                        index = 0;
1712:                    }
1713:                } // endwhile
1714:
1715:                // Get any remaining bytes in hold
1716:                if (index != 0) {
1717:                    ret ^= hold;
1718:                }
1719:
1720:                return ret;
1721:            }
1722:
1723:            /**
1724:             * Returns a string representation of the Blob.
1725:             * Includes length and checksum.
1726:             * @see #printContents
1727:             *
1728:             */
1729:            public synchronized String toString() {
1730:                return new String("Blob[length=" + size + ";checksum="
1731:                        + toHex(checksum()) + "]");
1732:            }
1733:
1734:            /**
1735:             * Prints the contents of this Blob.
1736:             * Formats the data neatly and prints it to System.out.
1737:             * @see #toString
1738:             *
1739:             */
1740:            public synchronized void printContents() {
1741:
1742:                int x, bytesPast;
1743:                String holdStr;
1744:                char rep[] = new char[16];
1745:                byte b;
1746:                long cksum = checksum();
1747:
1748:                // where to go?
1749:                PrintStream o = System.out;
1750:
1751:                // current output width
1752:                int currWidth = 86;
1753:
1754:                holdStr = ("Blob: length = " + size + " -- Checksum = "
1755:                        + toHex(cksum) + " ");
1756:                o.print(holdStr);
1757:                o.println(strstr((currWidth - holdStr.length()), '-'));
1758:
1759:                // If no data, just print the last line and get outta' here
1760:                if (size == 0) {
1761:                    o.println(strstr(currWidth, '-'));
1762:                    return;
1763:                }
1764:
1765:                o.print("     0 | ");
1766:
1767:                bytesPast = 0;
1768:                beginEnumeration(0);
1769:                while (hasMoreBytes()) {
1770:
1771:                    // print next byte
1772:                    b = nextByte();
1773:                    o.print(toHex(b));
1774:
1775:                    // get the representation
1776:                    if (between(b, 32, 126)) {
1777:                        rep[bytesPast % 16] = (char) b;
1778:                    } else {
1779:                        rep[bytesPast % 16] = '.';
1780:                    }
1781:
1782:                    // incriment pointer
1783:                    bytesPast++;
1784:
1785:                    if ((bytesPast % 16) == 0) {
1786:                        // print out representation
1787:                        o.print("   <");
1788:                        for (x = 0; x < 16; x++) {
1789:                            o.print(rep[x]);
1790:                        }
1791:                        o.println(">");
1792:
1793:                        // Start of new line
1794:                        if (hasMoreBytes()) {
1795:                            holdStr = Integer.toString(bytesPast);
1796:                            o.print(spaces(6 - holdStr.length()));
1797:                            o.print(holdStr);
1798:                            o.print(" | ");
1799:                        }
1800:
1801:                    } else if ((bytesPast % 4) == 0) {
1802:                        // end of 4-byte chunk
1803:                        o.print("   ");
1804:
1805:                    } else {
1806:                        o.print(' ');
1807:                    } // endif
1808:
1809:                } // endwhile
1810:
1811:                if ((bytesPast % 16) != 0) {
1812:                    // write out some filler spaces
1813:                    for (x = (bytesPast % 16); x < 16; x++) {
1814:                        o.print("  ");
1815:                        rep[x] = ' ';
1816:
1817:                        if ((x % 4) == 0) {
1818:                            // end of (what would have been a) 4-byte chunk
1819:                            o.print("   ");
1820:                        } else {
1821:                            o.print(' ');
1822:                        } // endif
1823:                    }
1824:
1825:                    // print out representation
1826:                    o.print("   <");
1827:                    for (x = 0; x < 16; x++) {
1828:                        o.print(rep[x]);
1829:                    }
1830:                    o.println(">");
1831:                }
1832:
1833:                // Write last dashed line
1834:                holdStr = ("---------------"
1835:                        + strstr(String.valueOf(size).length(), '-')
1836:                        + "--- Checksum = " + toHex(cksum) + " ");
1837:                o.print(holdStr);
1838:                o.println(strstr((currWidth - holdStr.length()), '-'));
1839:            }
1840:
1841:            ////////////////////////////////////////////////////////////
1842:            ////////////////////////////////////////////////////////////
1843:            ////////////////////////////////////////////////////////////
1844:            //
1845:            //       INTERNAL METHODS
1846:            //
1847:
1848:            /**
1849:             * Appends a new node to the end of the internal list.
1850:             * @param newNodeSize Size of the new node to create.
1851:             *
1852:             */
1853:            protected void appendNode(int newNodeSize) {
1854:
1855:                // Create a new node -- put it on the end of the list
1856:                tail.next = new BlobNode(newNodeSize);
1857:
1858:                // Set the new tail
1859:                tail = tail.next;
1860:            }
1861:
1862:            /**
1863:             * Seeks a position within the internal list.
1864:             * Takes an offset from the beginning and sets the 'curr' pointer
1865:             * to the reqested node and returns the offset within that node
1866:             * to the correct position.
1867:             * @param pos The position within the Blob to seek.
1868:             * @return The offest into the current node where the requested
1869:             * byte can be found.
1870:             * @exception java.lang.IndexOutOfBoundsException If pos is
1871:             * outside range of Blob.
1872:             *
1873:             */
1874:            protected int seek(int pos) {
1875:                if (!between(pos, 0, (size - 1))) {
1876:                    throw new IndexOutOfBoundsException("Seek past end:"
1877:                            + "pos=" + pos + "   " + "size=" + size);
1878:
1879:                }
1880:
1881:                int bytesPast = 0;
1882:                curr = this .head;
1883:
1884:                while ((curr.size + bytesPast) <= pos) {
1885:
1886:                    // Go to next node...
1887:                    bytesPast += curr.size;
1888:                    curr = curr.next;
1889:                }
1890:
1891:                // Return the offset into the current node.
1892:                return (pos - bytesPast);
1893:            }
1894:
1895:            /**
1896:             * Finds the node before the given node.
1897:             * This is the one whose next pointer is the given node.
1898:             * @return the node before the supplied node or
1899:             * null if the given node is the head node.
1900:             * @exception java.util.NoSuchElementException if the node is
1901:             * not found in the list.
1902:             *
1903:             */
1904:            protected BlobNode findBefore(BlobNode target) {
1905:
1906:                BlobNode bn;
1907:
1908:                if (target == head) {
1909:                    return null;
1910:                }
1911:
1912:                bn = head;
1913:                while (bn.next != target) {
1914:                    if (bn.next == null) {
1915:                        throw new NoSuchElementException(
1916:                                "Couldn't find BlobNode");
1917:                    }
1918:                    bn = bn.next;
1919:                }
1920:                return bn;
1921:
1922:            } // end findBefore()
1923:
1924:            //
1925:            // Internal Enumeration Methods
1926:            //
1927:
1928:            /**
1929:             * Sets up an enumeration of the bytes of the Blob
1930:             * starting from a particular point.
1931:             * @param pos The location from which to begin enumerating bytes.
1932:             * @exception java.lang.IndexOutOfBoundsException If pos and len are
1933:             * outside range of Blob.
1934:             *
1935:             */
1936:            protected synchronized void beginEnumeration(int pos) {
1937:
1938:                // Set the current position null
1939:                enumerationNode = null;
1940:
1941:                // Is the data within bounds?
1942:                if (!between(pos, 0, (size - 1))) {
1943:                    throw new IndexOutOfBoundsException();
1944:                }
1945:
1946:                // Find the position
1947:                enumerationPos = seek(pos);
1948:                enumerationNode = curr;
1949:
1950:                // We're ready to begin enumerating the bytes
1951:            } // end beginInternalEnumeration()
1952:
1953:            /**
1954:             * Returns 'true' if the Blob has more bytes, 'false' if empty.
1955:             *
1956:             */
1957:            protected synchronized boolean hasMoreBytes() {
1958:                return (enumerationNode != null);
1959:            }
1960:
1961:            /**
1962:             * Returns the next byte in the Blob.
1963:             * @exception java.util.NoSuchElementException If there are no more bytes
1964:             * in the current enumeration
1965:             *
1966:             */
1967:            protected synchronized byte nextByte() {
1968:
1969:                if (enumerationNode == null) {
1970:                    throw new NoSuchElementException(
1971:                            "Past end of current Enumeration");
1972:                }
1973:
1974:                byte ret = enumerationNode.data[enumerationPos++];
1975:
1976:                // check to see if we're at the end of the current node
1977:                if (enumerationPos == enumerationNode.size) {
1978:
1979:                    // At end, go to next node
1980:                    enumerationNode = enumerationNode.next;
1981:                    enumerationPos = 0;
1982:                }
1983:
1984:                // All done
1985:                return ret;
1986:            } // end nextByte()
1987:
1988:            //
1989:            // Serialization Methods
1990:            //
1991:
1992:            /**
1993:             * A specialized object write routine.
1994:             * This is because java gets a stack overflow error when
1995:             * trying to write the linked list.  Damn!
1996:             *
1997:             */
1998:            protected void writeObject(ObjectOutputStream out)
1999:                    throws IOException {
2000:                out.defaultWriteObject();
2001:
2002:                byte a[] = getBytes();
2003:                out.writeObject(a);
2004:            }
2005:
2006:            /**
2007:             * A specialized object read routine.
2008:             *
2009:             */
2010:            protected void readObject(ObjectInputStream in) throws IOException,
2011:                    ClassNotFoundException {
2012:                in.defaultReadObject();
2013:
2014:                // Create a new node to contain the one massive chunk of data.
2015:                byte a[] = (byte[]) in.readObject();
2016:                head = new BlobNode(nodeSize, a, 0, a.length);
2017:
2018:                tail = head;
2019:                size = a.length;
2020:            }
2021:
2022:            /*
2023:             // to test blob as an input stream ...
2024:             public static void main(String args[])
2025:             throws Exception
2026:             {
2027:             Blob b1 = new Blob();
2028:             Blob b2 = new Blob();
2029:             Blob b3 = new Blob();
2030:
2031:             int size = 2048;
2032:             try
2033:             {
2034:             size = Integer.parseInt(args[0]);
2035:             }
2036:             catch (Exception ignore) {}
2037:
2038:             System.out.println("size: " + size);
2039:
2040:             // load b1
2041:             for (int i = 0; i < size; i++)
2042:             {
2043:             int c = i;
2044:             b1.append((byte)c);
2045:             // System.out.println(i + ": appending: " + c + " " + (int)(b1.byteAt(i)));
2046:             }
2047:
2048:             // load b2 from b1 via the input stream
2049:             b2.read(b1.inputStream());
2050:
2051:             // load b3 from b1 (not using stream)
2052:             b3.append(b1);
2053:
2054:             System.out.println("b1 size: " + b1.length());
2055:             System.out.println("b2 size: " + b2.length());
2056:             System.out.println("b3 size: " + b3.length());
2057:
2058:             // compare
2059:             if (b2.equals(b1))
2060:             {
2061:             System.out.println(" b2.equals(b1) passed");
2062:             }
2063:             else
2064:             {
2065:             System.out.println(" b2.equals(b1) failed");
2066:             }
2067:
2068:             // compare
2069:             if (b3.equals(b1))
2070:             {
2071:             System.out.println(" b3.equals(b1) passed");
2072:             }
2073:             else
2074:             {
2075:             System.out.println(" b3.equals(b1) failed");
2076:             }
2077:
2078:             try
2079:             {
2080:             System.out.println("comparing b1 and b2 byte by byte");
2081:             for (int i = 0; i < b1.length(); i++)
2082:             {
2083:             if (b1.byteAt(i) != b2.byteAt(i))
2084:             {
2085:             System.out.println("mismatch at: " + i + " : b1 = " + b1.byteAt(i) + " : b2 = " + b2.byteAt(i));
2086:             }
2087:             }
2088:             System.out.println(b1.length() + " bytes compared");
2089:             }
2090:             catch (Exception e) { System.out.println(e); }
2091:
2092:             try
2093:             {
2094:             System.out.println("comparing b1 and b3 byte by byte");
2095:             for (int i = 0; i < b1.length(); i++)
2096:             {
2097:             if (b1.byteAt(i) != b3.byteAt(i))
2098:             {
2099:             System.out.println("mismatch at: " + i + " : b1 = " + b1.byteAt(i) + " : b3 = " + b3.byteAt(i));
2100:             }
2101:             }
2102:             System.out.println(b1.length() + " bytes compared");
2103:             }
2104:             catch (Exception e) { System.out.println(e); }
2105:
2106:             InputStream in = b1.inputStream();
2107:             for (int i = 0; i < b1.length(); i++)
2108:             {
2109:             int available = in.available();
2110:             int b = in.read();
2111:             System.out.println(i + " : avail= " + available + " : read = " + b);
2112:             }
2113:             System.out.println("final avail= " + in.available());
2114:             in.close();
2115:
2116:             }	// main
2117:             */
2118:
2119:        } // end Blob
2120:
2121:        /**
2122:         * A node in the underlying data-storage structure of the Blob class.
2123:         * @see Blob
2124:         * @author T. Gee
2125:         *
2126:         */
2127:        class BlobNode implements  Cloneable, Serializable {
2128:
2129:            /**
2130:             * 
2131:             */
2132:            private static final long serialVersionUID = 3833749897282336560L;
2133:
2134:            /**
2135:             * The next BlobNode in the list, null if last node.
2136:             */
2137:            BlobNode next = null;
2138:
2139:            /**
2140:             * The number of bytes currently in this node
2141:             */
2142:            int size;
2143:
2144:            /**
2145:             * The actual data held by this node
2146:             */
2147:            byte data[];
2148:
2149:            /**
2150:             * Constructs a new, empty node with the requested capacity.
2151:             * @param capacity The size of this node's internal storage.
2152:             *
2153:             */
2154:            public BlobNode(int capacity) {
2155:                data = new byte[capacity];
2156:                size = 0;
2157:            }
2158:
2159:            /**
2160:             * Constructs a new node initialized with the supplied data.
2161:             * @param capacity The size of the new node -- if smaller than
2162:             * 'data', will be increased to accomidate all of data.
2163:             * @param data The data to use to initialize this BlobNode.
2164:             *
2165:             */
2166:            public BlobNode(int capacity, byte arr[], int startPos, int len) {
2167:                data = new byte[Math.max(capacity, len)];
2168:                System.arraycopy(arr, startPos, data, 0, len);
2169:                size = len;
2170:            }
2171:
2172:            /**
2173:             * Gets the number of bytes of free storage within this node.
2174:             * @return the number of free bytes.
2175:             *
2176:             */
2177:            public int freespace() {
2178:                return data.length - size;
2179:            }
2180:
2181:            /**
2182:             * Clones the node.
2183:             *
2184:             */
2185:            public Object clone() {
2186:                BlobNode b = new BlobNode(data.length);
2187:
2188:                System.arraycopy(this .data, 0, b.data, 0, size);
2189:                b.size = this .size;
2190:
2191:                return b;
2192:            }
2193:
2194:        } // end BlobNode
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.