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