Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/ydp/jai/StructuredStorage.java


1   /*
2    * The contents of this file are subject to the  JAVA ADVANCED IMAGING
3    * SAMPLE INPUT-OUTPUT CODECS AND WIDGET HANDLING SOURCE CODE  License
4    * Version 1.0 (the "License"); You may not use this file except in
5    * compliance with the License. You may obtain a copy of the License at
6    * http://www.sun.com/software/imaging/JAI/index.html
7    *
8    * Software distributed under the License is distributed on an "AS IS"
9    * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
10   * the License for the specific language governing rights and limitations
11   * under the License. 
12   *
13   * The Original Code is JAVA ADVANCED IMAGING SAMPLE INPUT-OUTPUT CODECS
14   * AND WIDGET HANDLING SOURCE CODE. 
15   * The Initial Developer of the Original Code is: Sun Microsystems, Inc..
16   * Portions created by: _______________________________________
17   * are Copyright (C): _______________________________________
18   * All Rights Reserved.
19   * Contributor(s): _______________________________________
20   */
21  
22  package org.ydp.jai;
23  
24  import java.io.ByteArrayInputStream;
25  import java.io.InputStream;
26  import java.io.IOException;
27  import java.io.RandomAccessFile;
28  import java.util.StringTokenizer;
29  
30  //
31  // NOTE -- all 'long' variables are really at most 32 bits,
32  // corresponding to Microsoft 'ULONG' variables.
33  //
34  
35  // Temporary assumptions:
36  //
37  // All streams, including the ministream, are shorter than 2GB (size < 2GB)
38  // 
39  // There are < 2^31 directory entries (#streams < 2^31)
40  //
41  
42  class SSDirectoryEntry {
43  
44      int index;
45      String name;
46      long size;
47      long startSector;
48      long SIDLeftSibling;
49      long SIDRightSibling;
50      long SIDChild;
51      
52      public SSDirectoryEntry(int index,
53                              String name,
54                              long size,
55                              long startSector,
56                              long SIDLeftSibling,
57                              long SIDRightSibling,
58                              long SIDChild) {
59          this.name = name;
60          this.index = index;
61          this.size = size;
62          this.startSector = startSector;
63          this.SIDLeftSibling = SIDLeftSibling;
64          this.SIDRightSibling = SIDRightSibling;
65          this.SIDChild = SIDChild;
66  
67          // System.out.println("Got a directory entry named " + name +
68          //                    " (index " + index + ")");
69          // System.out.println("Start sector = " + startSector);
70      }
71  
72      public String getName() {
73          return name;
74      }
75  
76      public long getSize() {
77          return size;
78      }
79  
80      public long getStartSector() {
81          return startSector;
82      }
83  
84      public long getSIDLeftSibling() {
85          return SIDLeftSibling;
86      }
87  
88      public long getSIDRightSibling() {
89          return SIDRightSibling;
90      }
91  
92      public long getSIDChild() {
93          return SIDChild;
94      }
95  }
96  
97  public class StructuredStorage {
98  
99      SeekableStream file;
100 
101     // Header fields
102     private int sectorShift; // ULONG -- must be between 1 and 31
103     private int miniSectorShift;
104     private long csectFat;
105     private long sectDirStart;
106     private long miniSectorCutoff;
107     private long sectMiniFatStart;
108     private long csectMiniFat;
109     private long sectDifStart;
110     private long csectDif;
111     private long[] sectFat;
112 
113     // FAT, MiniFAT, and ministream in unrolled format
114     // private long[] FAT; // ULONG -- only 2G entries max
115     private long[] MINIFAT; // ULONG -- only 2G entries max
116     private SSDirectoryEntry[] DIR;
117 
118     private SeekableStream miniStream;
119     private SeekableStream FATStream;
120 
121     // The index of the current directory
122     long cwdIndex = -1L;
123 
124     public StructuredStorage(SeekableStream file) throws IOException {
125         this.file = file;
126 
127         // Read fields from the header
128         getHeader();
129 
130         // Read the FAT
131         getFat();
132 
133         // Read the MiniFAT
134         getMiniFat();
135 
136         // Read the directory
137         getDirectory();
138 
139         // Read the MiniStream
140         getMiniStream();
141     }
142 
143     private void getHeader() throws IOException {
144         file.seek(0x1e);
145         this.sectorShift = file.readUnsignedShortLE();
146 
147         file.seek(0x20);
148         this.miniSectorShift = file.readUnsignedShortLE();
149 
150         file.seek(0x2c);
151         this.csectFat = file.readUnsignedIntLE();
152 
153         file.seek(0x30);
154         this.sectDirStart = file.readUnsignedIntLE();
155 
156         file.seek(0x38);
157         this.miniSectorCutoff = file.readUnsignedIntLE();
158 
159         file.seek(0x3c);
160         this.sectMiniFatStart = file.readUnsignedIntLE();
161 
162         file.seek(0x40);
163         this.csectMiniFat = file.readUnsignedIntLE();
164 
165         file.seek(0x44);
166         this.sectDifStart = file.readUnsignedIntLE();
167         
168         file.seek(0x48);
169         this.csectDif = file.readUnsignedIntLE();
170         
171         this.sectFat = new long[109];
172         file.seek(0x4c);
173         for (int i = 0; i < 109; i++) {
174             this.sectFat[i] = file.readUnsignedIntLE();
175         }
176     }
177 
178     private void getFat() throws IOException {
179         int size = getSectorSize();
180         int sectsPerFat = size/4;
181         int fatsPerDif = size/4 - 1;
182 
183         int numFATSectors = (int)(csectFat + csectDif*fatsPerDif);
184         long[] FATSectors = new long[numFATSectors];
185         int count = 0;
186 
187         for (int i = 0; i < 109; i++) {
188             long sector = sectFat[i];
189             if (sector == 0xFFFFFFFFL) {
190                 break;
191             }
192 
193             FATSectors[count++] = getOffsetOfSector(sectFat[i]);
194         }
195 
196         if (csectDif > 0) {
197             long dif = sectDifStart;
198             byte[] difBuf = new byte[size];
199             
200             for (int i = 0; i < csectDif; i++) {
201                 readSector(dif, difBuf, 0);
202                 for (int j = 0; j < fatsPerDif; j++) {
203                     int sec = FPXUtils.getIntLE(difBuf, 4*j);
204                     FATSectors[count++] = getOffsetOfSector(sec);
205                 }
206                 
207                 dif = FPXUtils.getIntLE(difBuf, size - 4);
208             }
209         }
210 
211         FATStream = new SegmentedSeekableStream(file,
212                                                 FATSectors,
213                                                 size,
214                                                 numFATSectors*size,
215                                                 true);
216     }
217     
218     private void getMiniFat() throws IOException {
219         int size = getSectorSize();
220         int sectsPerFat = size/4;
221         int index = 0;
222         
223         this.MINIFAT = new long[(int)(csectMiniFat*sectsPerFat)];
224         
225         long sector = sectMiniFatStart;
226         byte[] buf = new byte[size];
227         while (sector != 0xFFFFFFFEL) {
228             readSector(sector, buf, 0);
229             for (int j = 0; j < sectsPerFat; j++) {
230                 MINIFAT[index++] = FPXUtils.getIntLE(buf, 4*j);
231             }
232             sector = getFATSector(sector);
233         }
234     }
235 
236     private void getDirectory() throws IOException {
237         int size = getSectorSize();
238         long sector = sectDirStart;
239 
240         // Count the length of the directory in sectors
241         int numDirectorySectors = 0;
242         while (sector != 0xFFFFFFFEL) {
243             sector = getFATSector(sector);
244             ++numDirectorySectors;
245         }
246 
247         int directoryEntries = 4*numDirectorySectors;
248         this.DIR = new SSDirectoryEntry[directoryEntries];
249 
250         sector = sectDirStart;
251         byte[] buf = new byte[size];
252         int index = 0;
253         while (sector != 0xFFFFFFFEL) {
254             readSector(sector, buf, 0);
255             
256             int offset = 0;
257             for (int i = 0; i < 4; i++) { // 4 dirents per sector
258                 // We divide the length by 2 for now even though
259                 // the spec says not to...
260                 int length = FPXUtils.getShortLE(buf, offset + 0x40);
261 
262                 String name = FPXUtils.getString(buf, offset + 0x00, length);
263                 long SIDLeftSibling =
264                     FPXUtils.getUnsignedIntLE(buf, offset + 0x44);
265                 long SIDRightSibling =
266                     FPXUtils.getUnsignedIntLE(buf, offset + 0x48);
267                 long SIDChild = FPXUtils.getUnsignedIntLE(buf, offset + 0x4c);
268                 long startSector =
269                     FPXUtils.getUnsignedIntLE(buf, offset + 0x74);
270                 long streamSize = FPXUtils.getUnsignedIntLE(buf, offset + 0x78);
271                 
272                 DIR[index] = new SSDirectoryEntry(index,
273                                                   name,
274                                                   streamSize,
275                                                   startSector,
276                                                   SIDLeftSibling,
277                                                   SIDRightSibling,
278                                                   SIDChild);
279                 ++index;
280                 offset += 128;
281             }
282 
283             sector = getFATSector(sector);
284         }
285     }
286 
287     private void getMiniStream() throws IOException {
288         int length = getLength(0L);
289         int sectorSize = getSectorSize();
290         int sectors = (int)((length + sectorSize - 1)/sectorSize);
291 
292         long[] segmentPositions = new long[sectors];
293 
294         long sector = getStartSector(0);
295 
296         for (int i = 0; i < sectors - 1; i++) {
297             segmentPositions[i] = getOffsetOfSector(sector);
298             sector = getFATSector(sector);
299         }
300         segmentPositions[sectors - 1] = getOffsetOfSector(sector);
301 
302         miniStream = new SegmentedSeekableStream(file,
303                                                  segmentPositions,
304                                                  sectorSize,
305                                                  length,
306                                                  true);
307     }
308 
309     private int getSectorSize() {
310         return 1 << sectorShift;
311     }
312 
313     private long getOffsetOfSector(long sector) {
314         return sector*getSectorSize() + 512;
315     }
316 
317     private int getMiniSectorSize() {
318         return 1 << miniSectorShift;
319     }
320 
321     private long getOffsetOfMiniSector(long sector) {
322         return sector*getMiniSectorSize();
323     }
324 
325     private void readMiniSector(long sector, byte[] buf,
326                                 int offset, int length) 
327         throws IOException {
328         miniStream.seek(getOffsetOfMiniSector(sector));
329         miniStream.read(buf, offset, length);
330     }
331 
332     private void readMiniSector(long sector, byte[] buf, int offset) 
333         throws IOException {
334         readMiniSector(sector, buf, offset, getMiniSectorSize());
335     }
336 
337     private void readSector(long sector, byte[] buf, int offset, int length) 
338         throws IOException {
339         file.seek(getOffsetOfSector(sector));
340         file.read(buf, offset, length);
341     }
342 
343     private void readSector(long sector, byte[] buf, int offset) 
344         throws IOException {
345         readSector(sector, buf, offset, getSectorSize());
346     }
347 
348     private SSDirectoryEntry getDirectoryEntry(long index) {
349         // Assume #streams < 2^31
350         return DIR[(int)index];
351     }
352 
353     private long getStartSector(long index) {
354         // Assume #streams < 2^31
355         return DIR[(int)index].getStartSector();
356     }
357 
358     private int getLength(long index) {
359         // Assume #streams < 2^31
360         // Assume size < 2GB
361         return (int)DIR[(int)index].getSize();
362     }
363 
364     private long getFATSector(long sector) throws IOException {
365         FATStream.seek(4*sector);
366         return FATStream.readUnsignedIntLE();
367     }
368 
369     private long getMiniFATSector(long sector) {
370         return MINIFAT[(int)sector];
371     }
372 
373     private int getCurrentIndex() {
374         return -1;
375     }
376 
377     private int getIndex(String name, int index) {
378         return -1;
379     }
380 
381     private long searchDirectory(String name, long index) {
382         if (index == 0xFFFFFFFFL) {
383             return -1L;
384         }
385 
386         SSDirectoryEntry dirent = getDirectoryEntry(index);
387 
388         if (name.equals(dirent.getName())) {
389             return index;
390         } else {
391             long lindex =
392                 searchDirectory(name, dirent.getSIDLeftSibling());
393             if (lindex != -1L) {
394                 return lindex;
395             }
396 
397             long rindex =
398                 searchDirectory(name, dirent.getSIDRightSibling());
399             if (rindex != -1L) {
400                 return rindex;
401             }
402         }
403 
404         return -1L;
405     }
406 
407     // Public methods
408 
409     public void changeDirectoryToRoot() {
410         cwdIndex = getDirectoryEntry(0L).getSIDChild();
411     }
412 
413     public boolean changeDirectory(String name) {
414         long index = searchDirectory(name, cwdIndex);
415         if (index != -1L) {
416             cwdIndex = getDirectoryEntry(index).getSIDChild();
417             return true;
418         } else {
419             return false;
420         }
421     }
422 
423     private long getStreamIndex(String name) {
424         // Move down the directory hierarchy
425         long index = cwdIndex;
426         
427         StringTokenizer st = new StringTokenizer(name, "/");
428         boolean firstTime = true;
429         while (st.hasMoreTokens()) {
430             String tok = st.nextToken();
431             
432             if (!firstTime) {
433                 index = getDirectoryEntry(index).getSIDChild();
434             } else {
435                 firstTime = false;
436             }
437             index = searchDirectory(tok, index);
438         }
439 
440         return index;
441     }
442     
443     public byte[] getStreamAsBytes(String name) throws IOException {
444         long index = getStreamIndex(name);
445         if (index == -1L) {
446             return null;
447         }
448 
449         // Cast index to int (streams < 2^31) and cast stream size to an
450         // int (size < 2GB)
451         int length = getLength(index);
452         byte[] buf = new byte[length];
453 
454         if (length > miniSectorCutoff) {
455             int sectorSize = getSectorSize();
456             int sectors = (int)((length + sectorSize - 1)/sectorSize);
457 
458             long sector = getStartSector(index);
459             int offset = 0;
460             for (int i = 0; i < sectors - 1; i++) {
461                 readSector(sector, buf, offset, sectorSize);
462                 offset += sectorSize;
463                 sector = getFATSector(sector);
464             }
465             
466             readSector(sector, buf, offset, length - offset);
467         } else {
468             int sectorSize = getMiniSectorSize();
469             int sectors = (int)((length + sectorSize - 1)/sectorSize);
470             
471             long sector = getStartSector(index);
472 
473             // Assume ministream size < 2GB
474             int offset = 0;
475             for (int i = 0; i < sectors - 1; i++) {
476                 long miniSectorOffset = getOffsetOfMiniSector(sector);
477                 readMiniSector(sector, buf, offset, sectorSize);
478                 offset += sectorSize;
479                 sector = getMiniFATSector(sector);
480             }
481             readMiniSector(sector, buf, offset, length - offset);
482         }
483 
484         return buf;
485     }
486 
487     public SeekableStream getStream(String name) throws IOException {
488         long index = getStreamIndex(name);
489         if (index == -1L) {
490             return null;
491         }
492 
493         // Cast index to int (streams < 2^31) and cast stream size to an
494         // int (size < 2GB)
495         int length = getLength(index);
496 
497         long[] segmentPositions;
498         int sectorSize, sectors;
499 
500         if (length > miniSectorCutoff) {
501             sectorSize = getSectorSize();
502             sectors = (int)((length + sectorSize - 1)/sectorSize);
503             segmentPositions = new long[sectors];
504             
505             long sector = getStartSector(index);
506             for (int i = 0; i < sectors - 1; i++) {
507                 segmentPositions[i] = getOffsetOfSector(sector);
508                 sector = getFATSector(sector);
509             }
510             segmentPositions[sectors - 1] = getOffsetOfSector(sector);
511 
512             return new SegmentedSeekableStream(file,
513                                                segmentPositions,
514                                                sectorSize,
515                                                length,
516                                                true);     
517         } else {
518             sectorSize = getMiniSectorSize();
519             sectors = (int)((length + sectorSize - 1)/sectorSize);
520             segmentPositions = new long[sectors];
521 
522             long sector = getStartSector(index);
523             for (int i = 0; i < sectors - 1; i++) {
524                 segmentPositions[i] = getOffsetOfMiniSector(sector);
525                 sector = getMiniFATSector(sector);
526             }
527             segmentPositions[sectors - 1] = getOffsetOfMiniSector(sector);
528 
529             return new SegmentedSeekableStream(miniStream,
530                                                segmentPositions,
531                                                sectorSize,
532                                                length,
533                                                true);
534         }
535     }
536 
537     public static void main(String[] args) {
538         try {
539             RandomAccessFile f = new RandomAccessFile(args[0], "r");
540             SeekableStream sis = new FileSeekableStream(f);
541             StructuredStorage ss = new StructuredStorage(sis);
542 
543             ss.changeDirectoryToRoot();
544 
545             byte[] s = ss.getStreamAsBytes("SummaryInformation");
546 
547             PropertySet ps = new PropertySet(new ByteArraySeekableStream(s));
548 
549             // Get the thumbnail property
550             byte[] thumb = ps.getBlob(17);
551 
552             // Emit it as a BMP file
553             System.out.print("BM");
554             int fs = (thumb.length - 8) + 14 + 40;
555             System.out.print((char)(fs & 0xff));
556             System.out.print((char)((fs >>  8) & 0xff));
557             System.out.print((char)((fs >> 16) & 0xff));
558             System.out.print((char)((fs >> 24) & 0xff));
559             System.out.print((char)0);
560             System.out.print((char)0);
561             System.out.print((char)0);
562             System.out.print((char)0);
563             System.out.print('6');
564             System.out.print((char)0);
565             System.out.print((char)0);
566             System.out.print((char)0);
567             for (int i = 8; i < thumb.length; i++) {
568                 System.out.print((char)(thumb[i] & 0xff));
569             }
570             
571         } catch (Exception e) {
572             e.printStackTrace();
573         }
574     }
575 }