Source Code Cross Referenced for CompressedGeometryFile.java in  » 6.0-JDK-Modules » java-3d » com » sun » j3d » utils » compression » 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 » 6.0 JDK Modules » java 3d » com.sun.j3d.utils.compression 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $RCSfile: CompressedGeometryFile.java,v $
003:         *
004:         * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * Redistribution and use in source and binary forms, with or without
007:         * modification, are permitted provided that the following conditions
008:         * are met:
009:         *
010:         * - Redistribution of source code must retain the above copyright
011:         *   notice, this list of conditions and the following disclaimer.
012:         *
013:         * - Redistribution in binary form must reproduce the above copyright
014:         *   notice, this list of conditions and the following disclaimer in
015:         *   the documentation and/or other materials provided with the
016:         *   distribution.
017:         *
018:         * Neither the name of Sun Microsystems, Inc. or the names of
019:         * contributors may be used to endorse or promote products derived
020:         * from this software without specific prior written permission.
021:         *
022:         * This software is provided "AS IS," without a warranty of any
023:         * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024:         * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025:         * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026:         * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027:         * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028:         * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029:         * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030:         * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031:         * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032:         * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033:         * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034:         * POSSIBILITY OF SUCH DAMAGES.
035:         *
036:         * You acknowledge that this software is not designed, licensed or
037:         * intended for use in the design, construction, operation or
038:         * maintenance of any nuclear facility.
039:         *
040:         * $Revision: 1.5 $
041:         * $Date: 2007/02/09 17:20:16 $
042:         * $State: Exp $
043:         */
044:
045:        package com.sun.j3d.utils.compression;
046:
047:        import java.io.FileNotFoundException;
048:        import java.io.IOException;
049:        import java.io.RandomAccessFile;
050:        import javax.media.j3d.CompressedGeometry;
051:        import javax.media.j3d.CompressedGeometryHeader;
052:
053:        //
054:        // The compressed geometry file format supported by this class has a 32
055:        // byte header followed by multiple compressed geometry objects.
056:        //
057:        // Each object consists of a block of compressed data and an 8-byte
058:        // individual block header describing its contents.
059:        //
060:        // The file ends with a directory data structure used for random access,
061:        // containing a 64-bit offset for each object in the order in which it
062:        // appears in the file.  This is also used to find the size of the largest
063:        // object in the file and must be present.
064:        //
065:
066:        /**
067:         * This class provides methods to read and write compressed geometry resource
068:         * files.  These files usually end with the .cg extension and support
069:         * sequential as well as random access to multiple compressed geometry
070:         * objects.
071:         *
072:         * @deprecated As of Java 3D 1.5, replaced by
073:         * com.sun.j3d.utils.geometry.compression.{@link com.sun.j3d.utils.geometry.compression.CompressedGeometryFile}.
074:         */
075:        public class CompressedGeometryFile {
076:            private static final boolean print = false;
077:            private static final boolean benchmark = false;
078:
079:            /**
080:             * The magic number which identifies the compressed geometry file type.
081:             */
082:            static final int MAGIC_NUMBER = 0xbaddfab4;
083:
084:            /**
085:             * Byte offset of the magic number from start of file.
086:             */
087:            static final int MAGIC_NUMBER_OFFSET = 0;
088:
089:            /**
090:             * Byte offset of the major version number from start of file.
091:             */
092:            static final int MAJOR_VERSION_OFFSET = 4;
093:
094:            /**
095:             * Byte offset of the minor version number from start of file.
096:             */
097:            static final int MINOR_VERSION_OFFSET = 8;
098:
099:            /**
100:             * Byte offset of the minor minor version number from start of file.
101:             */
102:            static final int MINOR_MINOR_VERSION_OFFSET = 12;
103:
104:            /**
105:             * Byte offset of the number of objects from start of file.
106:             */
107:            static final int OBJECT_COUNT_OFFSET = 16;
108:
109:            /**
110:             * Byte offset of the directory offset from start of file.
111:             * This offset is long word aligned since the directory offset is a long.
112:             */
113:            static final int DIRECTORY_OFFSET_OFFSET = 24;
114:
115:            /**
116:             * File header total size in bytes.
117:             */
118:            static final int HEADER_SIZE = 32;
119:
120:            /**
121:             * Byte offset of the object size from start of individual compressed
122:             * geometry block.
123:             */
124:            static final int OBJECT_SIZE_OFFSET = 0;
125:
126:            /**
127:             * Byte offset of the compressed geometry data descriptor from start of
128:             * individual compressed geometry block.
129:             */
130:            static final int GEOM_DATA_OFFSET = 4;
131:
132:            /**
133:             * Bits in compressed geometry data descriptor which encode the buffer type.
134:             */
135:            static final int TYPE_MASK = 0x03;
136:
137:            /**
138:             * Bit in compressed geometry data descriptor encoding presence of normals.
139:             */
140:            static final int NORMAL_PRESENT_MASK = 0x04;
141:
142:            /**
143:             * Bit in compressed geometry data descriptor encoding presence of colors.
144:             */
145:            static final int COLOR_PRESENT_MASK = 0x08;
146:
147:            /**
148:             * Bit in compressed geometry data descriptor encoding presence of alphas.
149:             */
150:            static final int ALPHA_PRESENT_MASK = 0x10;
151:
152:            /**
153:             * Value in compressed geometry data descriptor for a point buffer type.
154:             */
155:            static final int TYPE_POINT = 1;
156:
157:            /**
158:             * Value in compressed geometry data descriptor for a line buffer type.
159:             */
160:            static final int TYPE_LINE = 2;
161:
162:            /**
163:             * Value in compressed geometry data descriptor for a triangle buffer type.
164:             */
165:            static final int TYPE_TRIANGLE = 3;
166:
167:            /**
168:             * Block header total size in bytes.
169:             */
170:            static final int BLOCK_HEADER_SIZE = 8;
171:
172:            // The name of the compressed geometry resource file.
173:            String fileName = null;
174:
175:            // The major, minor, and subminor version number of the most recent
176:            // compressor used to compress any of the objects in the compressed
177:            // geometry resource file.
178:            int majorVersionNumber;
179:            int minorVersionNumber;
180:            int minorMinorVersionNumber;
181:
182:            // The number of objects in the compressed geometry resource file.
183:            int objectCount;
184:
185:            // The index of the current object in the file.
186:            int objectIndex = 0;
187:
188:            // The random access file associated with this instance.
189:            RandomAccessFile cgFile = null;
190:
191:            // The magic number identifying the file type.
192:            int magicNumber;
193:
194:            // These fields are set from each individual block of compressed geometry.
195:            byte cgBuffer[];
196:            int geomSize;
197:            int geomStart;
198:            int geomDataType;
199:
200:            // The directory of object offsets is read from the end of the file.
201:            long directory[];
202:            long directoryOffset;
203:
204:            // The object sizes are computed from the directory offsets.  These are
205:            // used to allocate a buffer large enough to hold the largest object and
206:            // to determine how many consecutive objects can be read into that buffer.
207:            int objectSizes[];
208:            int bufferObjectStart;
209:            int bufferObjectCount;
210:            int bufferNextObjectCount;
211:            int bufferNextObjectOffset;
212:
213:            // The shared compressed geometry header object.
214:            CompressedGeometryHeader cgh;
215:
216:            // Flag indicating file update.
217:            boolean fileUpdate = false;
218:
219:            /**
220:             * Construct a new CompressedGeometryFile instance associated with the
221:             * specified file.  An attempt is made to open the file with read-only
222:             * access; if this fails then a FileNotFoundException is thrown.
223:             *
224:             * @param file path to the compressed geometry resource file
225:             * @exception FileNotFoundException if file doesn't exist or
226:             * cannot be read
227:             * @exception IllegalArgumentException if the file is not a compressed
228:             * geometry resource file
229:             * @exception IOException if there is a header or directory read error
230:             */
231:            public CompressedGeometryFile(String file) throws IOException {
232:                this (file, false);
233:            }
234:
235:            /**
236:             * Construct a new CompressedGeometryFile instance associated with the
237:             * specified file.
238:             *
239:             * @param file path to the compressed geometry resource file
240:             * @param rw if true, opens the file for read and write access or attempts
241:             * to create one if it doesn't exist; if false, opens the file with
242:             * read-only access
243:             * @exception FileNotFoundException if file doesn't exist or
244:             * access permissions disallow access
245:             * @exception IllegalArgumentException if the file is not a compressed
246:             * geometry resource file
247:             * @exception IOException if there is a header or directory read error
248:             */
249:            public CompressedGeometryFile(String file, boolean rw)
250:                    throws IOException {
251:                // Open the file and read the file header.
252:                open(file, rw);
253:
254:                // Copy the file name.
255:                fileName = new String(file);
256:
257:                // Set up the file fields.
258:                initialize();
259:            }
260:
261:            /**
262:             * Construct a new CompressedGeometryFile instance associated with a
263:             * currently open RandomAccessFile.
264:             *
265:             * @param file currently open RandomAccessFile
266:             * @exception IllegalArgumentException if the file is not a compressed
267:             * geometry resource file
268:             * @exception IOException if there is a header or directory read error
269:             */
270:            public CompressedGeometryFile(RandomAccessFile file)
271:                    throws IOException {
272:                // Copy the file reference.
273:                cgFile = file;
274:
275:                // Set up the file fields.
276:                initialize();
277:            }
278:
279:            /**
280:             * Delete all compressed objects from this instance.  This method may only
281:             * be called after successfully creating a CompressedGeometryFile instance
282:             * with read-write access, so a corrupted or otherwise invalid resource
283:             * must be removed manually before it can be rewritten.  The close()
284:             * method must be called sometime after invoking clear() in order to write
285:             * out the new directory structure.
286:             * 
287:             * @exception IOException if clear fails
288:             */
289:            public void clear() throws IOException {
290:                // Truncate the file.
291:                cgFile.setLength(0);
292:
293:                // Set up the file fields.
294:                initialize();
295:            }
296:
297:            /**
298:             * Return a string containing the file name associated with this instance
299:             * or null if there is none.
300:             *
301:             * @return file name associated with this instance or null if there is
302:             * none
303:             */
304:            public String getFileName() {
305:                return fileName;
306:            }
307:
308:            /**
309:             * Return the major version number of the most recent compressor used to
310:             * compress any of the objects in this instance.
311:             *
312:             * @return major version number
313:             */
314:            public int getMajorVersionNumber() {
315:                return majorVersionNumber;
316:            }
317:
318:            /**
319:             * Return the minor version number of the most recent compressor used to
320:             * compress any of the objects in this instance.
321:             *
322:             * @return minor version number
323:             */
324:            public int getMinorVersionNumber() {
325:                return minorVersionNumber;
326:            }
327:
328:            /**
329:             * Return the subminor version number of the most recent compressor used to
330:             * compress any of the objects in this instance.
331:             *
332:             * @return subminor version number
333:             */
334:            public int getMinorMinorVersionNumber() {
335:                return minorMinorVersionNumber;
336:            }
337:
338:            /**
339:             * Return the number of compressed objects in this instance.
340:             *
341:             * @return number of compressed objects
342:             */
343:            public int getObjectCount() {
344:                return objectCount;
345:            }
346:
347:            /**
348:             * Return the current object index associated with this instance.  This is
349:             * the index of the object that would be returned by an immediately
350:             * following call to the readNext() method.  Its initial value is 0; -1
351:             * is returned if the last object has been read.
352:             *
353:             * @return current object index, or -1 if at end
354:             */
355:            public int getCurrentIndex() {
356:                if (objectIndex == objectCount)
357:                    return -1;
358:                else
359:                    return objectIndex;
360:            }
361:
362:            /**
363:             * Read the next compressed geometry object in the instance.  This is
364:             * initially the first object (index 0) in the instance; otherwise, it is
365:             * whatever object is next after the last one read.  The current object
366:             * index is incremented by 1 after the read.  When the last object is read
367:             * the index becomes invalid and an immediately subsequent call to
368:             * readNext() returns null.
369:             * 
370:             * @return a CompressedGeometry node component, or null if the last object
371:             * has been read
372:             * @exception IOException if read fails
373:             */
374:            public CompressedGeometry readNext() throws IOException {
375:                return readNext(cgBuffer.length);
376:            }
377:
378:            /**
379:             * Read all compressed geometry objects contained in the instance.  The
380:             * current object index becomes invalid; an immediately following call
381:             * to readNext() will return null.
382:             *
383:             * @return an array of CompressedGeometry node components.
384:             * @exception IOException if read fails
385:             */
386:            public CompressedGeometry[] read() throws IOException {
387:                long startTime = 0;
388:                CompressedGeometry cg[] = new CompressedGeometry[objectCount];
389:
390:                if (benchmark)
391:                    startTime = System.currentTimeMillis();
392:
393:                objectIndex = 0;
394:                setFilePointer(directory[0]);
395:                bufferNextObjectCount = 0;
396:
397:                for (int i = 0; i < objectCount; i++)
398:                    cg[i] = readNext(cgBuffer.length);
399:
400:                if (benchmark) {
401:                    long t = System.currentTimeMillis() - startTime;
402:                    System.out.println("read " + objectCount + " objects "
403:                            + cgFile.length() + " bytes in " + (t / 1000f)
404:                            + " sec.");
405:                    System.out.println((cgFile.length() / (float) t)
406:                            + " Kbytes/sec.");
407:                }
408:
409:                return cg;
410:            }
411:
412:            /**
413:             * Read the compressed geometry object at the specified index.  The
414:             * current object index is set to the subsequent object unless the last
415:             * object has been read, in which case the index becomes invalid and an
416:             * immediately following call to readNext() will return null.
417:             *
418:             * @param index compressed geometry object to read
419:             * @return a CompressedGeometry node component
420:             * @exception IndexOutOfBoundsException if object index is
421:             * out of range
422:             * @exception IOException if read fails
423:             */
424:            public CompressedGeometry read(int index) throws IOException {
425:                objectIndex = index;
426:
427:                if (objectIndex < 0) {
428:                    throw new IndexOutOfBoundsException(
429:                            "\nobject index must be >= 0");
430:                }
431:                if (objectIndex >= objectCount) {
432:                    throw new IndexOutOfBoundsException(
433:                            "\nobject index must be < " + objectCount);
434:                }
435:
436:                // Check if object is in cache.
437:                if ((objectIndex >= bufferObjectStart)
438:                        && (objectIndex < bufferObjectStart + bufferObjectCount)) {
439:                    if (print)
440:                        System.out.println("\ngetting object from cache\n");
441:
442:                    bufferNextObjectOffset = (int) (directory[objectIndex] - directory[bufferObjectStart]);
443:
444:                    bufferNextObjectCount = bufferObjectCount
445:                            - (objectIndex - bufferObjectStart);
446:
447:                    return readNext();
448:
449:                } else {
450:                    // Move file pointer to correct offset.
451:                    setFilePointer(directory[objectIndex]);
452:
453:                    // Force a read from current offset.  Disable cache read-ahead
454:                    // since cache hits are unlikely with random access.
455:                    bufferNextObjectCount = 0;
456:                    return readNext(objectSizes[objectIndex]);
457:                }
458:            }
459:
460:            /**
461:             * Add a compressed geometry node component to the end of the instance.
462:             * The current object index becomes invalid; an immediately following call
463:             * to readNext() will return null.  The close() method must be called at
464:             * some later time in order to create a valid compressed geometry file.
465:             *
466:             * @param cg a compressed geometry node component
467:             * @exception CapabilityNotSetException if unable to get compressed
468:             * geometry data from the node component
469:             * @exception IOException if write fails
470:             */
471:            public void write(CompressedGeometry cg) throws IOException {
472:                CompressedGeometryHeader cgh = new CompressedGeometryHeader();
473:                cg.getCompressedGeometryHeader(cgh);
474:
475:                // Update the read/write buffer size if necessary.
476:                if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
477:                    cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE];
478:                    if (print)
479:                        System.out.println("\ncgBuffer: reallocated "
480:                                + (cgh.size + BLOCK_HEADER_SIZE) + " bytes");
481:                }
482:
483:                cg.getCompressedGeometry(cgBuffer);
484:                write(cgh, cgBuffer);
485:            }
486:
487:            /**
488:             * Add a buffer of compressed geometry data to the end of the
489:             * resource. The current object index becomes invalid; an immediately
490:             * following call to readNext() will return null. The close() method must
491:             * be called at some later time in order to create a valid compressed
492:             * geometry file.
493:             *
494:             * @param cgh a CompressedGeometryHeader object describing the data.
495:             * @param geometry the compressed geometry data
496:             * @exception IOException if write fails
497:             */
498:            public void write(CompressedGeometryHeader cgh, byte geometry[])
499:                    throws IOException {
500:
501:                // Update the read/write buffer size if necessary.  It won't be used
502:                // in this method, but should be big enough to read any object in
503:                // the file, including the one to be written.
504:                if (cgh.size + BLOCK_HEADER_SIZE > cgBuffer.length) {
505:                    cgBuffer = new byte[cgh.size + BLOCK_HEADER_SIZE];
506:                    if (print)
507:                        System.out.println("\ncgBuffer: reallocated "
508:                                + (cgh.size + BLOCK_HEADER_SIZE) + " bytes");
509:                }
510:
511:                // Assuming backward compatibility, the version number of the file
512:                // should be the maximum of all individual compressed object versions.
513:                if ((cgh.majorVersionNumber > majorVersionNumber)
514:                        || ((cgh.majorVersionNumber == majorVersionNumber) && (cgh.minorVersionNumber > minorVersionNumber))
515:                        || ((cgh.majorVersionNumber == majorVersionNumber)
516:                                && (cgh.minorVersionNumber == minorVersionNumber) && (cgh.minorMinorVersionNumber > minorMinorVersionNumber))) {
517:
518:                    majorVersionNumber = cgh.majorVersionNumber;
519:                    minorVersionNumber = cgh.minorVersionNumber;
520:                    minorMinorVersionNumber = cgh.minorMinorVersionNumber;
521:
522:                    this .cgh.majorVersionNumber = cgh.majorVersionNumber;
523:                    this .cgh.minorVersionNumber = cgh.minorVersionNumber;
524:                    this .cgh.minorMinorVersionNumber = cgh.minorMinorVersionNumber;
525:                }
526:
527:                // Get the buffer type and see what vertex components are present.
528:                int geomDataType = 0;
529:
530:                switch (cgh.bufferType) {
531:                case CompressedGeometryHeader.POINT_BUFFER:
532:                    geomDataType = TYPE_POINT;
533:                    break;
534:                case CompressedGeometryHeader.LINE_BUFFER:
535:                    geomDataType = TYPE_LINE;
536:                    break;
537:                case CompressedGeometryHeader.TRIANGLE_BUFFER:
538:                    geomDataType = TYPE_TRIANGLE;
539:                    break;
540:                }
541:
542:                if ((cgh.bufferDataPresent & CompressedGeometryHeader.NORMAL_IN_BUFFER) != 0)
543:                    geomDataType |= NORMAL_PRESENT_MASK;
544:
545:                if ((cgh.bufferDataPresent & CompressedGeometryHeader.COLOR_IN_BUFFER) != 0)
546:                    geomDataType |= COLOR_PRESENT_MASK;
547:
548:                if ((cgh.bufferDataPresent & CompressedGeometryHeader.ALPHA_IN_BUFFER) != 0)
549:                    geomDataType |= ALPHA_PRESENT_MASK;
550:
551:                // Allocate new directory and object size arrays if necessary.
552:                if (objectCount == directory.length) {
553:                    long newDirectory[] = new long[2 * objectCount];
554:                    int newObjectSizes[] = new int[2 * objectCount];
555:
556:                    System
557:                            .arraycopy(directory, 0, newDirectory, 0,
558:                                    objectCount);
559:                    System.arraycopy(objectSizes, 0, newObjectSizes, 0,
560:                            objectCount);
561:
562:                    directory = newDirectory;
563:                    objectSizes = newObjectSizes;
564:
565:                    if (print)
566:                        System.out
567:                                .println("\ndirectory and size arrays: reallocated "
568:                                        + (2 * objectCount) + " entries");
569:                }
570:
571:                // Update directory and object size array.
572:                directory[objectCount] = directoryOffset;
573:                objectSizes[objectCount] = cgh.size + BLOCK_HEADER_SIZE;
574:                objectCount++;
575:
576:                // Seek to the directory and overwrite from there.
577:                setFilePointer(directoryOffset);
578:                cgFile.writeInt(cgh.size);
579:                cgFile.writeInt(geomDataType);
580:                cgFile.write(geometry, 0, cgh.size);
581:                if (print)
582:                    System.out.println("\nwrote " + cgh.size
583:                            + " byte compressed object to " + fileName
584:                            + "\nfile offset " + directoryOffset);
585:
586:                // Update the directory offset.
587:                directoryOffset += cgh.size + BLOCK_HEADER_SIZE;
588:
589:                // Return end-of-file on next read.
590:                objectIndex = objectCount;
591:
592:                // Flag file update so close() will write out the directory.
593:                fileUpdate = true;
594:            }
595:
596:            /**
597:             * Release the resources associated with this instance.
598:             * Write out final header and directory if contents were updated.
599:             * This method must be called in order to create a valid compressed
600:             * geometry resource file if any updates were made.
601:             */
602:            public void close() {
603:                if (cgFile != null) {
604:                    try {
605:                        if (fileUpdate) {
606:                            writeFileDirectory();
607:                            writeFileHeader();
608:                        }
609:                        cgFile.close();
610:                    } catch (IOException e) {
611:                        // Don't propagate this exception.
612:                        System.out.println("\nException: " + e.getMessage());
613:                        System.out.println("failed to close " + fileName);
614:                    }
615:                }
616:                cgFile = null;
617:                cgBuffer = null;
618:                directory = null;
619:                objectSizes = null;
620:            }
621:
622:            //
623:            // Open the file.  Specifying a non-existent file creates a new one if
624:            // access permissions allow.
625:            //
626:            void open(String fname, boolean rw) throws FileNotFoundException,
627:                    IOException {
628:
629:                cgFile = null;
630:                String mode;
631:
632:                if (rw)
633:                    mode = "rw";
634:                else
635:                    mode = "r";
636:
637:                try {
638:                    cgFile = new RandomAccessFile(fname, mode);
639:                    if (print)
640:                        System.out.println("\n" + fname + ": opened mode "
641:                                + mode);
642:                } catch (FileNotFoundException e) {
643:                    // N.B. this exception is also thrown on access permission errors
644:                    throw new FileNotFoundException(e.getMessage() + "\n"
645:                            + fname + ": open mode " + mode + " failed");
646:                }
647:            }
648:
649:            //
650:            // Seek to the specified offset in the file.
651:            //
652:            void setFilePointer(long offset) throws IOException {
653:                cgFile.seek(offset);
654:
655:                // Reset number of objects that can be read sequentially from cache.
656:                bufferNextObjectCount = 0;
657:            }
658:
659:            //
660:            // Initialize directory, object size array, read/write buffer, and the
661:            // shared compressed geometry header.
662:            //
663:            void initialize() throws IOException {
664:                int maxSize = 0;
665:
666:                if (cgFile.length() == 0) {
667:                    // New file for writing: allocate nominal initial sizes for arrays.
668:                    objectCount = 0;
669:                    cgBuffer = new byte[32768];
670:                    directory = new long[16];
671:                    objectSizes = new int[directory.length];
672:
673:                    // Set fields as if they have been read.
674:                    magicNumber = MAGIC_NUMBER;
675:                    majorVersionNumber = 1;
676:                    minorVersionNumber = 0;
677:                    minorMinorVersionNumber = 0;
678:                    directoryOffset = HEADER_SIZE;
679:
680:                    // Write the file header.
681:                    writeFileHeader();
682:
683:                } else {
684:                    // Read the file header.
685:                    readFileHeader();
686:
687:                    // Check file type.
688:                    if (magicNumber != MAGIC_NUMBER) {
689:                        close();
690:                        throw new IllegalArgumentException("\n" + fileName
691:                                + " is not a compressed geometry file");
692:                    }
693:
694:                    // Read the directory and determine object sizes.
695:                    directory = new long[objectCount];
696:                    readDirectory(directoryOffset, directory);
697:
698:                    objectSizes = new int[objectCount];
699:                    for (int i = 0; i < objectCount - 1; i++) {
700:                        objectSizes[i] = (int) (directory[i + 1] - directory[i]);
701:                        if (objectSizes[i] > maxSize)
702:                            maxSize = objectSizes[i];
703:                    }
704:
705:                    if (objectCount > 0) {
706:                        objectSizes[objectCount - 1] = (int) (directoryOffset - directory[objectCount - 1]);
707:
708:                        if (objectSizes[objectCount - 1] > maxSize)
709:                            maxSize = objectSizes[objectCount - 1];
710:                    }
711:
712:                    // Allocate a buffer big enough to read the largest object.
713:                    cgBuffer = new byte[maxSize];
714:
715:                    // Move to the first object.
716:                    setFilePointer(HEADER_SIZE);
717:                }
718:
719:                // Set up common parts of the compressed geometry object header.
720:                cgh = new CompressedGeometryHeader();
721:                cgh.majorVersionNumber = this .majorVersionNumber;
722:                cgh.minorVersionNumber = this .minorVersionNumber;
723:                cgh.minorMinorVersionNumber = this .minorMinorVersionNumber;
724:
725:                if (print) {
726:                    System.out.println(fileName + ": " + objectCount
727:                            + " objects");
728:                    System.out.println("magic number 0x"
729:                            + Integer.toHexString(magicNumber)
730:                            + ", version number " + majorVersionNumber + "."
731:                            + minorVersionNumber + "."
732:                            + minorMinorVersionNumber);
733:                    System.out.println("largest object is " + maxSize
734:                            + " bytes");
735:                }
736:            }
737:
738:            //
739:            // Read the file header.
740:            // 
741:            void readFileHeader() throws IOException {
742:                byte header[] = new byte[HEADER_SIZE];
743:
744:                try {
745:                    setFilePointer(0);
746:                    if (cgFile.read(header) != HEADER_SIZE) {
747:                        close();
748:                        throw new IOException("failed header read");
749:                    }
750:                } catch (IOException e) {
751:                    if (cgFile != null) {
752:                        close();
753:                    }
754:                    throw e;
755:                }
756:
757:                magicNumber = ((header[MAGIC_NUMBER_OFFSET + 0] & 0xff) << 24)
758:                        | ((header[MAGIC_NUMBER_OFFSET + 1] & 0xff) << 16)
759:                        | ((header[MAGIC_NUMBER_OFFSET + 2] & 0xff) << 8)
760:                        | ((header[MAGIC_NUMBER_OFFSET + 3] & 0xff));
761:
762:                majorVersionNumber = ((header[MAJOR_VERSION_OFFSET + 0] & 0xff) << 24)
763:                        | ((header[MAJOR_VERSION_OFFSET + 1] & 0xff) << 16)
764:                        | ((header[MAJOR_VERSION_OFFSET + 2] & 0xff) << 8)
765:                        | ((header[MAJOR_VERSION_OFFSET + 3] & 0xff));
766:
767:                minorVersionNumber = ((header[MINOR_VERSION_OFFSET + 0] & 0xff) << 24)
768:                        | ((header[MINOR_VERSION_OFFSET + 1] & 0xff) << 16)
769:                        | ((header[MINOR_VERSION_OFFSET + 2] & 0xff) << 8)
770:                        | ((header[MINOR_VERSION_OFFSET + 3] & 0xff));
771:
772:                minorMinorVersionNumber = ((header[MINOR_MINOR_VERSION_OFFSET + 0] & 0xff) << 24)
773:                        | ((header[MINOR_MINOR_VERSION_OFFSET + 1] & 0xff) << 16)
774:                        | ((header[MINOR_MINOR_VERSION_OFFSET + 2] & 0xff) << 8)
775:                        | ((header[MINOR_MINOR_VERSION_OFFSET + 3] & 0xff));
776:
777:                objectCount = ((header[OBJECT_COUNT_OFFSET + 0] & 0xff) << 24)
778:                        | ((header[OBJECT_COUNT_OFFSET + 1] & 0xff) << 16)
779:                        | ((header[OBJECT_COUNT_OFFSET + 2] & 0xff) << 8)
780:                        | ((header[OBJECT_COUNT_OFFSET + 3] & 0xff));
781:
782:                directoryOffset = ((long) (header[DIRECTORY_OFFSET_OFFSET + 0] & 0xff) << 56)
783:                        | ((long) (header[DIRECTORY_OFFSET_OFFSET + 1] & 0xff) << 48)
784:                        | ((long) (header[DIRECTORY_OFFSET_OFFSET + 2] & 0xff) << 40)
785:                        | ((long) (header[DIRECTORY_OFFSET_OFFSET + 3] & 0xff) << 32)
786:                        | ((long) (header[DIRECTORY_OFFSET_OFFSET + 4] & 0xff) << 24)
787:                        | ((long) (header[DIRECTORY_OFFSET_OFFSET + 5] & 0xff) << 16)
788:                        | ((long) (header[DIRECTORY_OFFSET_OFFSET + 6] & 0xff) << 8)
789:                        | ((long) (header[DIRECTORY_OFFSET_OFFSET + 7] & 0xff));
790:            }
791:
792:            //
793:            // Write the file header based on current field values.
794:            //
795:            void writeFileHeader() throws IOException {
796:                setFilePointer(0);
797:                try {
798:                    cgFile.writeInt(MAGIC_NUMBER);
799:                    cgFile.writeInt(majorVersionNumber);
800:                    cgFile.writeInt(minorVersionNumber);
801:                    cgFile.writeInt(minorMinorVersionNumber);
802:                    cgFile.writeInt(objectCount);
803:                    cgFile.writeInt(0); // long word alignment
804:                    cgFile.writeLong(directoryOffset);
805:                    if (print)
806:                        System.out.println("wrote file header for " + fileName);
807:                } catch (IOException e) {
808:                    throw new IOException(e.getMessage()
809:                            + "\ncould not write file header for " + fileName);
810:                }
811:            }
812:
813:            //
814:            // Read the directory of compressed geometry object offsets.
815:            //
816:            void readDirectory(long offset, long[] directory)
817:                    throws IOException {
818:
819:                byte buff[] = new byte[directory.length * 8];
820:                setFilePointer(offset);
821:
822:                try {
823:                    cgFile.read(buff);
824:                    if (print)
825:                        System.out.println("read " + buff.length
826:                                + " byte directory");
827:                } catch (IOException e) {
828:                    throw new IOException(e.getMessage() + "\nfailed to read "
829:                            + buff.length + " byte directory, offset " + offset
830:                            + " in file " + fileName);
831:                }
832:
833:                for (int i = 0; i < directory.length; i++) {
834:                    directory[i] = ((long) (buff[i * 8 + 0] & 0xff) << 56)
835:                            | ((long) (buff[i * 8 + 1] & 0xff) << 48)
836:                            | ((long) (buff[i * 8 + 2] & 0xff) << 40)
837:                            | ((long) (buff[i * 8 + 3] & 0xff) << 32)
838:                            | ((long) (buff[i * 8 + 4] & 0xff) << 24)
839:                            | ((long) (buff[i * 8 + 5] & 0xff) << 16)
840:                            | ((long) (buff[i * 8 + 6] & 0xff) << 8)
841:                            | ((long) (buff[i * 8 + 7] & 0xff));
842:                }
843:            }
844:
845:            //
846:            // Write the file directory.
847:            //
848:            void writeFileDirectory() throws IOException {
849:                setFilePointer(directoryOffset);
850:
851:                int directoryAlign = (int) (directoryOffset % 8);
852:                if (directoryAlign != 0) {
853:                    // Align to long word before writing directory of long offsets.
854:                    byte bytes[] = new byte[8 - directoryAlign];
855:
856:                    try {
857:                        cgFile.write(bytes);
858:                        if (print)
859:                            System.out.println("wrote " + (8 - directoryAlign)
860:                                    + " bytes long alignment");
861:                    } catch (IOException e) {
862:                        throw new IOException(e.getMessage()
863:                                + "\ncould not write " + directoryAlign
864:                                + " bytes to long word align directory for "
865:                                + fileName);
866:                    }
867:                    directoryOffset += 8 - directoryAlign;
868:                }
869:
870:                try {
871:                    for (int i = 0; i < objectCount; i++)
872:                        cgFile.writeLong(directory[i]);
873:
874:                    if (print)
875:                        System.out.println("wrote file directory for "
876:                                + fileName);
877:                } catch (IOException e) {
878:                    throw new IOException(e.getMessage()
879:                            + "\ncould not write directory for " + fileName);
880:                }
881:            }
882:
883:            //
884:            // Get the next compressed object in the file, either from the read-ahead
885:            // cache or from the file itself.
886:            // 
887:            CompressedGeometry readNext(int bufferReadLimit) throws IOException {
888:                if (objectIndex == objectCount)
889:                    return null;
890:
891:                if (bufferNextObjectCount == 0) {
892:                    // No valid objects are in the cache.
893:                    int curSize = 0;
894:                    bufferObjectCount = 0;
895:
896:                    // See how much we have room to read.
897:                    for (int i = objectIndex; i < objectCount; i++) {
898:                        if (curSize + objectSizes[i] > bufferReadLimit)
899:                            break;
900:                        curSize += objectSizes[i];
901:                        bufferObjectCount++;
902:                    }
903:
904:                    // Try to read that amount.
905:                    try {
906:                        int n = cgFile.read(cgBuffer, 0, curSize);
907:                        if (print)
908:                            System.out.println("\nread " + n + " bytes from "
909:                                    + fileName);
910:                    } catch (IOException e) {
911:                        throw new IOException(e.getMessage()
912:                                + "\nfailed to read " + curSize
913:                                + " bytes, object " + objectIndex + " in file "
914:                                + fileName);
915:                    }
916:
917:                    // Point at the first object in the buffer.
918:                    bufferObjectStart = objectIndex;
919:                    bufferNextObjectCount = bufferObjectCount;
920:                    bufferNextObjectOffset = 0;
921:                }
922:
923:                // Get block header info.
924:                geomSize = ((cgBuffer[bufferNextObjectOffset
925:                        + OBJECT_SIZE_OFFSET + 0] & 0xff) << 24)
926:                        | ((cgBuffer[bufferNextObjectOffset
927:                                + OBJECT_SIZE_OFFSET + 1] & 0xff) << 16)
928:                        | ((cgBuffer[bufferNextObjectOffset
929:                                + OBJECT_SIZE_OFFSET + 2] & 0xff) << 8)
930:                        | ((cgBuffer[bufferNextObjectOffset
931:                                + OBJECT_SIZE_OFFSET + 3] & 0xff));
932:
933:                geomDataType = ((cgBuffer[bufferNextObjectOffset
934:                        + GEOM_DATA_OFFSET + 0] & 0xff) << 24)
935:                        | ((cgBuffer[bufferNextObjectOffset + GEOM_DATA_OFFSET
936:                                + 1] & 0xff) << 16)
937:                        | ((cgBuffer[bufferNextObjectOffset + GEOM_DATA_OFFSET
938:                                + 2] & 0xff) << 8)
939:                        | ((cgBuffer[bufferNextObjectOffset + GEOM_DATA_OFFSET
940:                                + 3] & 0xff));
941:
942:                // Get offset of compressed geometry data from start of buffer.
943:                geomStart = bufferNextObjectOffset + BLOCK_HEADER_SIZE;
944:
945:                if (print) {
946:                    System.out.println("\nobject " + objectIndex
947:                            + "\nfile offset " + directory[objectIndex]
948:                            + ", buffer offset " + bufferNextObjectOffset);
949:                    System.out.println("size " + geomSize + " bytes, "
950:                            + "data descriptor 0x"
951:                            + Integer.toHexString(geomDataType));
952:                }
953:
954:                // Update cache info.
955:                bufferNextObjectOffset += objectSizes[objectIndex];
956:                bufferNextObjectCount--;
957:                objectIndex++;
958:
959:                return newCG(geomSize, geomStart, geomDataType);
960:            }
961:
962:            //
963:            // Construct and return a compressed geometry node.
964:            //
965:            CompressedGeometry newCG(int geomSize, int geomStart,
966:                    int geomDataType) {
967:                cgh.size = geomSize;
968:                cgh.start = geomStart;
969:
970:                if ((geomDataType & TYPE_MASK) == TYPE_POINT)
971:                    cgh.bufferType = CompressedGeometryHeader.POINT_BUFFER;
972:                else if ((geomDataType & TYPE_MASK) == TYPE_LINE)
973:                    cgh.bufferType = CompressedGeometryHeader.LINE_BUFFER;
974:                else if ((geomDataType & TYPE_MASK) == TYPE_TRIANGLE)
975:                    cgh.bufferType = CompressedGeometryHeader.TRIANGLE_BUFFER;
976:
977:                cgh.bufferDataPresent = 0;
978:
979:                if ((geomDataType & NORMAL_PRESENT_MASK) != 0)
980:                    cgh.bufferDataPresent |= CompressedGeometryHeader.NORMAL_IN_BUFFER;
981:
982:                if ((geomDataType & COLOR_PRESENT_MASK) != 0)
983:                    cgh.bufferDataPresent |= CompressedGeometryHeader.COLOR_IN_BUFFER;
984:
985:                if ((geomDataType & ALPHA_PRESENT_MASK) != 0)
986:                    cgh.bufferDataPresent |= CompressedGeometryHeader.ALPHA_IN_BUFFER;
987:
988:                return new CompressedGeometry(cgh, cgBuffer);
989:            }
990:
991:            /**
992:             * Release file resources when this object is garbage collected.
993:             */
994:            protected void finalize() {
995:                close();
996:            }
997:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.