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

Quick Search    Search Deep

Source code: com/flexstor/flexdbserver/services/asset/FPOExtract.java


1   /*
2    * FPOExtract.java
3    *
4    * Copyright $Date: 2003/08/11 02:22:28 $ FLEXSTOR.net Inc.
5    *
6    * This work is licensed for use and distribution under license terms found at
7    * http://www.flexstor.org/license.html
8    *
9    */
10  
11  package com.flexstor.flexdbserver.services.asset;
12  
13  import java.io.EOFException;
14  import java.io.IOException;
15  import java.util.Vector;
16  
17  import com.flexstor.common.io.xfile.FlexXRandomAccessFile;
18  import com.flexstor.common.util.Diagnostic;
19  
20  
21  /**
22  * Locate and extract the image from a Xinet EPSF
23  *
24  */
25  public class FPOExtract
26    {
27    public final static String IDENTIFIER="$Id: FPOExtract.java,v 1.4 2003/08/11 02:22:28 aleric Exp $";
28    
29    
30    
31    // Image input parameters
32    protected String  sOutputFile       = null;
33    
34    // Image output parameters
35    protected int     nImageWidth       = 0;
36    protected int     nImageHeight      = 0;
37    protected int     nImageXResolution = 0;
38    protected int     nImageYResolution = 0;
39    protected long    nFilesize         = 0;
40    protected int     nImageLength      = 0;
41    
42    protected String  sImageType        = "";
43    protected String  sImageSubType     = "0";
44    
45    protected int     nAdditionalItems  = 0;  
46    protected boolean bError            = false;
47  
48    /************* TEST MODE ************/
49    protected boolean bTest  = false;  
50    /************************************/
51    
52    /**
53    *
54    *
55    */
56    public FPOExtract()
57      {
58      } // constructor
59      
60    
61    /**
62    *
63    *
64    */
65    public boolean extractImage(String sParentFile, String sOutputFile, String sImageToProcess)
66      {
67      return extractImage(sParentFile, sOutputFile, sImageToProcess, "");
68      }
69  
70    
71    /**
72    *
73    *
74    */
75    public boolean extractImage(String sParentFile, String sOutputFile, String sImageToProcess, String sImageName)
76      {
77      return processImages(sParentFile, sOutputFile, sImageName, sImageToProcess, false);
78      }
79    
80    /**
81    *
82    *
83    */
84    public boolean getImageInfo(String sParentFile,  String sImageToProcess)
85      {
86      return getImageInfo(sParentFile, sImageToProcess, "");
87      }
88    
89    /**
90    *
91    *
92    */
93    public boolean getImageInfo(String sParentFile,  String sImageToProcess, String sImageName)
94      {
95      return processImages(sParentFile, "", sImageName, sImageToProcess, true);
96      }
97    
98    /**
99    *
100   *
101   */
102   public boolean getMapInfo(String sParentFile)
103     {
104     printDiagnosticMessage("Processing file: " + sParentFile);
105     return processImages(sParentFile, "", "", "-1", true);
106     } // getMapInfo
107   
108   /**
109   *
110   *
111   */
112   protected boolean processImages(String  sParentFile, 
113                                   String  sOutputFile, 
114                                   String  sName, 
115                                   String  sImageToProcess, 
116                                   boolean bInfo)
117     {
118     boolean bResult    = true;
119     boolean bReadToEnd = false;
120     this.sOutputFile   = sOutputFile;
121   
122     // Initialize image parameters
123     sImageType        = "";
124     nImageWidth       = 0;
125     nImageHeight      = 0;
126     nImageXResolution = 0;
127     nImageYResolution = 0;
128     nFilesize         = 0;
129     
130     // Open the parent file
131     FlexXRandomAccessFile fParentFile = openFile(sParentFile, "r");
132     if (fParentFile == null)
133       {
134       return false;
135       }
136 
137     // Get the file map containing pointers to images and headers
138     Vector vMap = getMap(fParentFile);
139     if (vMap == null)
140       {
141       printDiagnosticMessage("Image file not FPO: " + sParentFile);      
142       return false;
143       }
144     
145     if ((sImageToProcess == "-1") || (bTest == true))
146       {
147       printMap(vMap);
148       if (sImageToProcess == "-1")
149         {
150         return true;
151         }
152       }
153     
154     // Get the pointer for the image specified from the file map
155     long nImagePointer = getImagePointer(fParentFile, vMap, sName, sImageToProcess);
156     if (nImagePointer == -1)
157       {
158       closeFile(fParentFile);
159       return false;
160       }
161       
162     if (bTest)
163       {
164       printDiagnosticMessage("Image block pointer: " + Long.toHexString(nImagePointer));
165       }
166 
167     // Set the filesize
168     nFilesize = (long)nImageLength;  
169     
170     // Get the image parameters if requested
171     if (bInfo == true)
172       {
173       if (getInfo(fParentFile, nImagePointer) == false)
174         {
175         closeFile(fParentFile);
176         return false;
177         }          
178       } // bGetInfo if   
179     
180     else // Extract and copy the image
181       {
182       // If want to read to the end of the file, set image length to -1
183  //     if (bReadToEnd == true)
184  //       {
185  //       nImageLength = -1;  
186  //       }
187     
188       if (bTest)
189         {
190         // Add the appropriate extension to the filename
191         if (sImageType.equals("") == false)
192           {
193           sOutputFile = sOutputFile + "." + sImageType;
194           }
195       
196         printDiagnosticMessage("Output file  : " + sOutputFile);
197         printDiagnosticMessage("Image pointer: " + Long.toHexString(nImagePointer));
198         printDiagnosticMessage("Image type   : " + sImageType);
199         }  
200 
201       // Copy the image to the file name specified
202       if (extractAndCopyImage(fParentFile,
203                               nImagePointer, 
204                               nImageLength, 
205                               sOutputFile, 
206                               false) == false)
207         {
208         closeFile(fParentFile);
209         return false;
210         }
211       } // bInfo else
212     
213     if (bTest == true)
214       {
215       printDiagnosticMessage("Current file pointer: " + Long.toHexString(getCurrentPos(fParentFile)));
216       }
217     
218     closeFile(fParentFile);
219     return bResult;
220     } // processImages
221     
222   
223   /**
224   * Get the location of the image specified by type (FPO, etc) and sequence number (1,2..)
225   * Non-image blocks may be interspersed between the image blocks so must check
226   * the block format to make sure that it is an image block.  The image format is 
227   * remembered for later info extraction.
228   *
229   */
230   protected long getImagePointer(FlexXRandomAccessFile fParentFile, 
231                                  Vector              vMap, 
232                                  String              sName, 
233                                  String              sImageToProcess)
234     {
235     int  nImagePointer = -1;
236     long nCurrentPos   = -1;
237     
238     // sImageToProcess selects the image within the named group
239     // It can be specified as an int (1,2,3..) or as an image type
240     // The allowed types are <EPS, TIF, EPSORTIF>
241     int nImageToProcess = 0;
242     try
243       {
244       nImageToProcess = Integer.parseInt(sImageToProcess);
245       
246       // Appears to be a number (exception not thrown)
247       sImageToProcess = "";
248       }
249       
250     catch (NumberFormatException e)
251       {
252       // Not a number, its an image type specification
253       nImageToProcess = 0;
254       }
255     
256     // Check the name, in none specified, default to FPO
257     if (sName.equals("") == true)
258       {
259       sName = "FPO";
260       }
261     
262     // Is the image map vector valid?
263     if ((vMap == null) || (vMap.size() == 0))
264       {
265       return -1;
266       }
267       
268     // Scan the map for the image pointers with the correct name (FPO, PICT, ...)
269     // Select the correct image in this sequence per nImageToProcess or
270     // sImageToProcess, whichever is specified
271     int nImageNumber = 1;
272     for (int i=0; i<vMap.size(); i++)
273       {
274       nImageLength = 0;
275       sImageType   = "";
276       
277       ImagePointer refMappedPointer = (ImagePointer)vMap.elementAt(i);
278       if (refMappedPointer.getName().trim().equals(sName) == true)          
279         {
280         nImagePointer = refMappedPointer.getPointer();    
281           
282         // Add the offset value to the image pointer
283         nImagePointer += 0x100;
284     
285         // Go to the image
286         if (goToFileLocation(fParentFile, (long)nImagePointer) == false)
287           {
288           nCurrentPos = -1;
289           break;
290           }
291 
292         // Read the image size (next 4 bytes)
293         nImageLength = readInt(fParentFile);
294 
295         // Get and save the current file position (this is the start of the image)
296         nCurrentPos = getCurrentPos(fParentFile);
297         if (nCurrentPos == -1)
298           {
299           nCurrentPos = -1;
300           break;
301           }
302  
303         if (bTest)
304          {
305          printDiagnosticMessage("Image pointer: " + Long.toHexString(nCurrentPos));
306          }
307 
308         // Is this an image block or other data block (they can be intermixed)
309         // Check for the image identifier, is it a valid image?
310         if (checkFormat(fParentFile) == false)
311           {
312           // An error occurred
313           nCurrentPos = -1;
314           break;
315           }
316       
317         // Is the block an image block
318         // If not continue in the loop, getting the next block
319         // for the specified image name (FPO, etc)
320         if (sImageType.equals("") == false)
321           {
322           // It's an image block, so check to see if it is the one
323           // specified by the sequence number or the image type
324           if (nImageToProcess != 0)
325             {
326             // An image sequence number was specified
327             if (nImageNumber == nImageToProcess)
328               {
329               // Correct image found, quit
330               break;
331               }
332           
333             else
334               {
335               // The block was an image but not the right one 
336               // so increment the image number, and try again
337               nImageNumber++;
338               }
339             } // nImageNumber if
340             
341           else
342             {
343             // sImageToProcess denotes a file type
344             if ((sImageToProcess.equals("EPSORTIF")) && 
345                 ((sImageType.equals("eps")) || (sImageType.equals("tif"))))
346               {
347               break;
348               }
349               
350             if ((sImageToProcess.equals("EPS")) && 
351                 (sImageType.equals("eps")))
352               {
353               break;
354               }
355               
356             if ((sImageToProcess.equals("TIF")) && 
357                 (sImageType.equals("tif")))
358               {
359               break;
360               }
361             } // nImageNumber else
362           } // sImageType if
363         
364         else
365           {
366           // Block is not an image
367           if (bTest)
368             {
369             printDiagnosticMessage("Block is not an image: " + Long.toHexString(nCurrentPos));
370             }
371           }
372         } // equals(sName)
373       } // for i
374     
375     if (sImageType.equals("") == true)
376       {
377       nCurrentPos = -1;  
378       }
379       
380     if (nCurrentPos == -1)
381       {
382       printDiagnosticMessage("Image not found in map for params: " + sName + ", " + nImageToProcess);  
383       }
384       
385     return nCurrentPos;
386     } // getImageToProcess
387    
388   /**
389   *
390   *
391   */
392   protected boolean getInfo(FlexXRandomAccessFile fFile, long nBlockStartPos)
393     {
394     boolean bResult = true;
395     
396     // Note that the current file position is just after the format-determining header info
397     
398     if (sImageType.equals("eps") == true)
399       {
400       if (getEpsInfo(fFile) == false) 
401         {
402         return false;
403         }
404       }
405       
406     else if (sImageType.equals("gif") == true)
407       {
408       if (getGifInfo(fFile) == false)
409         {
410         return false;
411         }
412       }
413       
414     else if (sImageType.equals("tif") == true)
415       {
416       if (getTiffInfo(fFile) == false)
417         {
418         return false;
419         }
420       }
421       
422     else if (sImageType.equals("jpg") == true)
423       {
424       if (getJfifInfo(fFile, nBlockStartPos) == false)  
425         {
426         return false;
427         }
428       }
429       
430     else if ((sImageType.equals("pic")  == true) && 
431              (sImageSubType.equals("0") == true))
432       {
433       // Version 2 PICT
434       if (getPictInfo(fFile, nBlockStartPos, 2) == false)
435         {
436         return false;
437         }
438       }
439       
440     else if ((sImageType.equals("pic")  == true) && 
441              (sImageSubType.equals("1") == true))
442       {
443       // Version 1 PICT
444       if (getPictInfo(fFile, nBlockStartPos, 1) == false)
445         {
446         return false;
447         }
448       }
449       
450         
451     return bResult;
452     } // genfo
453   
454   
455   /**
456   *
457   *
458   */
459   protected boolean getEpsInfo(FlexXRandomAccessFile fFile)
460     {
461     boolean bResult = true;
462     String  sInfoIdentifier = "%ImageData:";
463     
464     // Read 'nLength' bytes from the current file position
465     int  nLength  = 512;
466     byte anData[] = readBytes(fFile, nLength);
467     if (anData == null)
468       {
469       bResult = false;
470       }
471     
472     // Convert the array data to a string, search it for the info identifier string
473     String sFileData = new String(anData);
474     
475     int nIndex = sFileData.indexOf(sInfoIdentifier);
476     if (nIndex == -1)
477       {
478       // Info identifier not found  
479       bResult = false;
480       }
481     
482     else
483       {
484       // Parse the image width and length
485       String sInfoString = sFileData.substring(nIndex + sInfoIdentifier.length());
486     
487       if (bTest == true)
488         {
489         printDiagnosticMessage("EPS Info string: " + sInfoString);
490         }
491         
492       String sSub = getSubString(sInfoString, 0, 4);
493       if ((sSub != null) && (sSub.length() != 0))
494         {
495         nImageWidth = getInt(sSub);        
496         }
497         
498       sSub = getSubString(sInfoString, 4, 8);
499       if ((sSub != null) && (sSub.length() != 0))
500         {
501         nImageHeight = getInt(sSub);        
502         }
503       } // nIndex else
504     
505     return bResult;
506     } // getEpsInfo
507   
508   
509   /**
510   *
511   *
512   */
513   protected boolean getGifInfo(FlexXRandomAccessFile fFile)
514     {
515     boolean bResult = true;
516     
517     // Read 'nLength' bytes from the current file position
518     int  nLength  = 256;
519     byte anData[] = readBytes(fFile, nLength);
520     if (anData == null)
521       {
522       bResult = false;
523       }
524     
525     // Get width
526     int nParam = 0;
527 //    nParam = getInt(anData, 1, 2);
528     nParam = getInt(anData[1], anData[0]);
529     nImageWidth = nParam;        
530       
531     // Get height
532 //    nParam = getInt(anData, 3, 2);
533     nParam = getInt(anData[3], anData[2]);
534     nImageHeight = nParam;        
535 
536     return bResult;
537     } // getGifInfo
538   
539   /**
540   *
541   *
542   */
543   protected boolean getPictInfo(FlexXRandomAccessFile fInputFile, long nBlockStartPos, int nPictVersion)
544     {
545     boolean bResult = true;
546     
547     // First go back to the start of the image block
548     if (goToFileLocation(fInputFile, nBlockStartPos) == false)
549       {
550       return false;
551       }
552     
553     // Get the Image File Header
554     byte anHeader[] = readBytes(fInputFile, 40);
555     if (anHeader == null)
556       {
557       return false;
558       }
559     
560     // Get the width and height of the image
561     // Get the bounding box parameters first
562     int nUppperLeftY = getInt(anHeader, 2, 2);
563     int nUppperLeftX = getInt(anHeader, 4, 2);
564     int nLowerRightY = getInt(anHeader, 6, 2);
565     int nLowerRightX = getInt(anHeader, 8, 2);
566 
567     nImageWidth  = nLowerRightX - nUppperLeftX;
568     nImageHeight = nLowerRightY - nUppperLeftY;
569     
570     // Get the resolutions
571     if (nPictVersion == 1)
572       {
573       // PICT version 1 doesn't support header info other than version and bounding rectangle
574       // therefore, no resolution.
575       nImageXResolution = 0;
576       nImageYResolution = 0;
577       }
578       
579     else
580       {
581       nImageXResolution = getInt(anHeader, 20, 2);
582       nImageYResolution = getInt(anHeader, 24, 2);
583       }
584       
585     return bResult;
586     } // getPictInfo
587   
588   /**
589   *
590   *
591   */
592   protected boolean getTiffInfo(FlexXRandomAccessFile fInputFile)
593     {
594     boolean bResult = true;
595     
596     // Save the current file position pointer
597     // This is the start of the Tiff image
598     long lCurrentPos = getCurrentPos(fInputFile);
599     if (lCurrentPos == -1)
600       {
601       return false;
602       }
603       
604     // Get the Image File Header
605     byte anHeader[] = readBytes(fInputFile, 8);
606     if (anHeader == null)
607       {
608       bResult = false;
609       }
610     
611     // Get the pointer to the Image File Directory (IFD) 
612     int nIfdPointer = getInt(anHeader, 2, 4);     
613     nIfdPointer = nIfdPointer & 0xffffffff;
614     
615     // The above pointer is relative to start of image
616     if (goToPointerLocation(fInputFile, nIfdPointer - 10) == false)
617       {
618       return false;
619       }
620     
621     // We should be at the start of the Image File Directory
622     // The first two bytes is the number of 12-byte tags it contains
623     // Tags should be in ascending order by tag
624     // This code assumes all relevant tags are contiguous    
625     // Read enough data to get the tags of interest
626     
627     // Get the number of tags
628     byte anTagCount[]  = readBytes(fInputFile, 2);
629     if (anTagCount == null)
630       {
631       return false;
632       }        
633     
634     int nTagCount = getInt(anTagCount, 0, 2); // Bytes 0-1
635     
636     // Read all tags (12 bytes each)
637     byte anIFD[] = readBytes(fInputFile, nTagCount * 12);
638     if (anIFD == null)
639       {
640       return false;
641       }
642       
643     // Tag construction: Bytes 0-1  The Tag identifier
644     //                   Bytes 2-3  The field Type (1-byte, 2-ascii, 3-short(16b), 4-long(32b), 5-rational(64b))
645     //                   Bytes 4-7  The count of the Type
646     //                   Bytes 8-11 The value offset or the value itself (msb-justified)
647     //
648     // Note: Technically, we should search for the tags to be more general. Since we only want two common tags
649     //       we will get them directly.
650     //       We are also not concerned about Endian here.
651     //       Also assuming Type 3 values (16 bit) for these tags.
652     //
653     // Get the Image Width Tag (id = 0100h)
654     int nTagIndex = findTag(anIFD, nTagCount, 0x100);
655     if (nTagIndex != -1)
656       {
657       nImageWidth = getInt(anIFD[nTagIndex + 8], anIFD[nTagIndex + 9]);
658       }
659     
660     // Get the Image Height Tag (id = 0101h)
661     nTagIndex = findTag(anIFD, nTagCount, 0x101);
662     if (nTagIndex != -1)
663       {
664       nImageHeight = getInt(anIFD[nTagIndex + 8], anIFD[nTagIndex + 9]);
665       }
666     
667     // Get the resolution unit tag (id = 0x128h)
668     // 1 = no absolute unit of measurement
669     // 2 = inches
670     // 3 = cm
671     int nResolutionUnit = 2; // default to inches
672     nTagIndex = findTag(anIFD, nTagCount, 0x128);
673     if (nTagIndex != -1)
674       {
675       nResolutionUnit = getInt(anIFD[nTagIndex + 8], anIFD[nTagIndex + 9]);
676       }
677     
678     // Get the X resolution tag (id = 0x11ah)
679     nImageXResolution = getTiffResolution(anIFD, 
680                                           fInputFile, 
681                                           lCurrentPos, 
682                                           0x11a, 
683                                           nTagCount, 
684                                           nResolutionUnit);
685                                         
686     // Get the Y resolution tag (id = 0x11bh)
687     nImageYResolution = getTiffResolution(anIFD, 
688                                           fInputFile, 
689                                           lCurrentPos, 
690                                           0x11b, 
691                                           nTagCount, 
692                                           nResolutionUnit);
693                                         
694       
695       
696     
697     return bResult;
698     } // getTiffInfo
699     
700   
701   /**
702   * Returns the index into the buffer of the specified tag
703   * Return -1 if tag not found
704   */
705   protected int findTag(byte anIFDBuffer[], int nTagCount, int nTag)
706     {
707     // Search thru the tags for the specified tag
708     // Tags immediately follow count
709     int nIndex = 0;
710     for (int i=0; i<nTagCount; i++)
711       {
712       if (getInt(anIFDBuffer, nIndex, 2) == nTag)
713         {
714         // Tag found
715         return nIndex;
716         }
717       
718       // Set index to the start of the next tag
719       nIndex += 12;
720       } // for i
721       
722     // Tag not found
723     return -1;
724     } // findTag
725   
726   /**
727   *
728   *
729   */
730   protected int getTiffResolution(byte anIFD[], 
731                                   FlexXRandomAccessFile fInputFile, 
732                                   long lCurrentPos, 
733                                   int  nTag, 
734                                   int  nTagCount, 
735                                   int  nResolutionUnit)
736     {
737     int nResolution = 0;
738     
739     // Get the requested resolution tag
740     int nTagIndex = findTag(anIFD, nTagCount, nTag);
741     if (nTagIndex != -1)
742       {
743       // First get the value offset relative from the beginning of the image
744       int nValueOffset = getInt(anIFD, nTagIndex + 8, 4);
745       
746       // Get the actual values (8 bytes)
747       if (goToFileLocation(fInputFile, lCurrentPos + (long)nValueOffset) == true)
748         {
749         byte anValue[] = readBytes(fInputFile, 8);
750       
751         // This tag is rational meaning that two 4-byte numbers, the numerator and denominator
752         int nNumerator   = getInt(anValue, 0, 4);
753         int nDenominator = getInt(anValue, 4, 4);
754 
755         if (nDenominator != 0)
756           {
757           nResolution = nNumerator/nDenominator;
758           }
759         
760         if (nResolutionUnit == 3)
761           {
762           // Convert from centimeters to inches
763           nResolution = (nResolution * 254)/100;
764           }
765         } // goToFileLocation if
766       } // nTagIndex if 
767     
768     return nResolution;
769     } // getTiffResolution
770   
771   /**
772   *
773   *
774   */
775   protected boolean getJfifInfo(FlexXRandomAccessFile fInputFile, long nBlockStartPos)
776     {
777     boolean bResult = true;
778     
779     // Obtain the image width/height. This is not contained in the JFIF header which
780     // may only have the image resolutions or aspect ratios. Must go to the JPEG header
781     // for width/height.
782     
783     // FFD8FFE0xxJFIF identifies the start of a JFIF image
784     //
785     // FFD8     - SOI (2 bytes 0-1)
786     // FFE0     - APPO (2 bytes 2-3)
787     // xx       - Byte length - remaining number of bytes in this header(2 bytes 4-5)
788     // JFIFx    - Identifier (5 bytes 6-10)
789     // xx       - Version (2 bytes 11-12)
790     // x        - Units (0=none so x&y densities specify pixel aspect ratios; 1=inches; 2=cm) (1 byte 13)
791     // xx       - X density (2 bytes 14-15)
792     // xx       - Y density (2 bytes 16-17)
793     // x        - X thumbnail pixel count (1 byte 18)
794     // x        - Y thumbnail pixel count (1 byte 19)
795     // FFDB     - End of this header (2 bytes 20-21)
796     //
797     // Scan the header for a field identified by FFC2 or FFC0
798     // Skip 3 bytes to the start of the 2-byte height and width fields
799     
800     // First go back to the start of the image block
801     if (goToFileLocation(fInputFile, nBlockStartPos) == false)
802       {
803       return false;
804       }
805     
806     // Get the Image File Header
807     byte anHeader[] = readBytes(fInputFile, 256);
808     if (anHeader == null)
809       {
810       return false;
811       }
812     
813     // Get the resolutions from the APPO header if they exist
814     // Determine first if the fields contain resolution (density) or aspect ratio
815     // Ignore if aspect ratio specified
816     if ((anHeader[13] == (byte)0x01) || (anHeader[13] == (byte)0x02))
817       {
818       int nXRes = getInt(anHeader, 14, 2);
819       int nYRes = getInt(anHeader, 16, 2);
820       
821       // If it is in cm, convert to inches
822       if (anHeader[13] == (byte)0x02)
823         {
824         nXRes = (nXRes * 254)/100;
825         nYRes = (nYRes * 254)/100;
826         }
827       } // anHeader if 
828     
829     // Now search for the width and height headers
830     int nIndex = -1;
831     for (int i=0; i<anHeader.length; i++) 
832       {
833       // Check for FFC0 or FFC2 headers  
834       if ((anHeader[i] == (byte)0xff) && 
835           ((anHeader[i+1] == (byte)0xc2) || (anHeader[i+1] == (byte)0xc0)))
836         {
837         nIndex = i;
838         break;
839         }
840       } // for
841     
842     if ((nIndex == -1) || (nIndex + 7 > anHeader.length))
843       {
844       // Field not found 
845       return false;
846       }
847     
848     // Get the height
849     int nHeight = getInt(anHeader[nIndex + 5], anHeader[nIndex + 6]);
850     nImageHeight = nHeight;
851     
852     // Get the width
853     int nWidth = getInt(anHeader[nIndex + 7], anHeader[nIndex + 8]);
854     nImageWidth = nWidth;
855     
856     return bResult; 
857     } // getJfifInfo
858     
859   
860   /**
861   *
862   *
863   */
864   protected int getInt(byte bHi, byte bLo)
865     {
866     int nParam = 0;
867     
868     nParam    = bHi;
869     nParam    = nParam << 8;
870     int nTemp = bLo;                // Java treats the byte as signed and the sign is carried over
871     nTemp     = nTemp & 0xff;       // into the int.  Thus must be masked.
872     nParam    = nParam | nTemp;
873     nParam    = nParam & 0xffff;
874       
875     return nParam;    
876     } // getInt
877   
878   
879   
880   /**
881   *
882   *
883   */
884   protected String getSubString(String sInput, int nStart, int nEnd)
885     {
886     String sResult = null;
887     try
888       {
889       sResult = sInput.substring(nStart, nEnd);
890       }
891       
892     catch(StringIndexOutOfBoundsException e)
893       {
894       printDiagnosticMessage("Error parsing info data" + e.toString());
895       }
896     
897     return sResult;
898     } // getSubString
899   
900   /**
901   *
902   *
903   */
904   protected int getInt(String sNumber)
905     {
906     int nResult = 0;
907 
908     try
909       {
910       nResult = Integer.parseInt(sNumber.trim());
911       }
912       
913     catch(NumberFormatException e)
914       {
915       printDiagnosticMessage("Error parsing info number" + e.toString());  
916       }
917       
918     return nResult;  
919     } // getInt
920     
921   /**
922   *
923   *
924   */
925   protected FlexXRandomAccessFile openFile(String sName, String sMode)
926     {
927     FlexXRandomAccessFile refRAF = null;
928 
929     try
930       {
931       refRAF = new FlexXRandomAccessFile(sName, sMode);
932       }
933 
934     catch(IOException e)
935       {
936       printDiagnosticMessage("Error opening file " + sName + ": " + e.toString());
937       bError = true;
938       }
939 
940     catch(SecurityException e)
941       {
942       printDiagnosticMessage("Error opening file " + sName + ": " + e.toString());
943       bError = true;
944       }
945     
946     return refRAF;
947     } // openFile
948 
949 
950   /**
951   * Reads the 4-byte integer at the current file location
952   *
953   */
954   protected int readInt(FlexXRandomAccessFile fFile)
955     {
956     int nBytesRead = -1;
957     
958     try
959       {
960       nBytesRead = fFile.readInt();
961       }
962       
963     catch(EOFException e)
964       {
965       printDiagnosticMessage("Error reading integer "  + ": " + e.toString());
966       nBytesRead = -1;
967       }
968       
969     catch(IOException e)
970       {
971       printDiagnosticMessage("Error reading integer " + ": " + e.toString());
972       nBytesRead = -1;
973       }
974 
975     return nBytesRead;
976     } // readInt
977   
978   
979   /**
980   * Seek to the specified offset from the current file position
981   *
982   */
983   protected boolean goToPointerLocation(FlexXRandomAccessFile fFile, int nOffset)
984     {
985     boolean bResult = true;
986   
987     try
988       {
989       fFile.skipBytes(nOffset);
990       }
991       
992     catch(EOFException e)
993       {
994       printDiagnosticMessage("Error seeking to pointer "  + ": " + e.toString());
995       bResult = false;
996       }
997       
998     catch(IOException e)
999       {
1000      printDiagnosticMessage("Error seeking to pointer " + ": " + e.toString());
1001      bResult = false;
1002      }
1003  
1004    
1005    return bResult;
1006    } // goToPointerLocation
1007  
1008  /**
1009  *
1010  *
1011  */
1012  protected boolean checkFormat(FlexXRandomAccessFile fFile)
1013    {
1014    boolean bResult = true;
1015    sImageType = "";
1016    
1017    // Table contains: the identifier to search for, the offset into the image
1018    // to search from, the type to give to the image once found, and the subtype
1019    // for a given type.
1020    String[][] saIdentifiers = {{"GIF87a"    , "0" , "gif", "0"}, 
1021                                {"GIF89a"    , "0" , "gif", "0"},
1022                                {"%!PS"      , "0" , "eps", "0"},
1023                                {"MM"        , "0" , "tif", "0"},
1024                                {"\\FFD8FFE0", "0" , "jpg", "0"},
1025                                {"\\001102FF", "10", "pic", "0"},   // PICT version 2
1026                                {"\\1101"    , "10", "pic", "1"}};  // PICT version 1
1027    
1028    // Save the current file position
1029    long nStartPos = getCurrentPos(fFile);
1030    int  nIdLength = 0;
1031    
1032    // Read 'n' bytes from the current file position
1033    byte anData[] = readBytes(fFile, 32);
1034    if (anData == null)
1035      {
1036      bResult = false;
1037      }
1038    
1039    for (int i=0; i<saIdentifiers.length; i++)
1040      {
1041      String sType   = saIdentifiers[i][0];
1042      String sOffset = saIdentifiers[i][1];
1043      int    nOffset = Integer.parseInt(sOffset);
1044      
1045      if (sType.startsWith("\\") == false)
1046        {
1047        // It's a string
1048        // Convert the file data to a string and compare 
1049        // it to the input type string
1050        nIdLength = sType.length() + nOffset;
1051        
1052        String sFileData = new String(anData);
1053        if (sFileData.startsWith(sType, nOffset) == true)
1054          {
1055          sImageType    = saIdentifiers[i][2];
1056          sImageSubType = saIdentifiers[i][3];
1057          bResult = true;
1058          break;
1059          }
1060        } // sType if
1061        
1062      else
1063        {
1064        // It's binary (hex)
1065        String sIdData = saIdentifiers[i][0];        
1066        boolean bMatch = true;
1067        int j = 1;
1068        int k = 0;
1069        
1070        // Match each byte in file data to hex chars in Id's
1071        while (j+1 < sIdData.length())
1072          {
1073          // Extract chars two at a time and convert hex to binary
1074          String sChars = sIdData.substring(j, j+2);
1075          
1076          // Convert hex to binary byte
1077          byte byteHex = Integer.decode("#" + sChars).byteValue();
1078          
1079          // Do they match?
1080          if (anData[k + nOffset] != byteHex)
1081            {
1082            // Mismatch so quit
1083            bMatch = false;
1084            break;
1085            }
1086          
1087          // Next two characters
1088          j += 2;
1089          k += 1;
1090          } // while
1091        
1092        if (bMatch == true)
1093          {
1094          sImageType    = saIdentifiers[i][2];
1095          sImageSubType = saIdentifiers[i][3];
1096          nIdLength  = k + nOffset;
1097          bResult    = true;
1098          break;
1099          }
1100        } // sType else
1101      } // for i
1102            
1103    // Reset the current file pos to the index after the ID
1104    goToFileLocation(fFile ,nStartPos + nIdLength);
1105    
1106    return bResult;
1107    } // isFormat
1108  
1109  
1110  /**
1111  *
1112  *
1113  */
1114  protected byte[] readBytes(FlexXRandomAccessFile fFile, int nCount)
1115    {
1116    int  nRead = -1;
1117    byte anInputData[] = new byte[nCount];
1118    
1119    try
1120      {
1121      nRead = fFile.read(anInputData);
1122      }
1123      
1124    catch(IOException e)
1125      {
1126      printDiagnosticMessage("Error reading bytes " + ": " + e.toString());
1127      anInputData = null;
1128      }
1129    
1130    if (nRead == -1)
1131      {
1132      // No more data, end of file
1133      anInputData = null;
1134      }
1135    
1136    return anInputData;
1137    } // readBytes
1138  
1139  
1140  /**
1141  *
1142  *
1143  */
1144  protected long getCurrentPos(FlexXRandomAccessFile fFile)
1145    {
1146    try
1147      {
1148      return fFile.getFilePointer();
1149      }
1150      
1151    catch(IOException e)
1152      {
1153      printDiagnosticMessage("Error getting file position " + ": " + e.toString());
1154      return -1;
1155      }
1156    } // getCurrentPos
1157  
1158  
1159  /**
1160  *
1161  *
1162  */
1163  protected boolean extractAndCopyImage(FlexXRandomAccessFile fParent,
1164                                        long    nFilePos, 
1165                                        int     nImageLength, 
1166                                        String  sThumbnailFile,
1167                                        boolean bDonotWrite)
1168    {
1169    boolean          bResult    = true;
1170    FlexXRandomAccessFile fThumbnail = null;
1171    
1172    // Create the thumbnail file if not in "DoNotWrite" mode
1173    if (bDonotWrite == false)
1174      {
1175      fThumbnail = openFile(sThumbnailFile, "rw");
1176      if (fThumbnail == null)
1177        {
1178        bResult = false;
1179        }
1180      }
1181      
1182    // Seek to the start of the image
1183    if (goToFileLocation(fParent, nFilePos) == false)
1184      {
1185      bResult = false;
1186      }
1187      
1188    // Copy the image
1189    if (copyBytes(fParent, fThumbnail, nImageLength) == false)
1190      {
1191      bResult = false;
1192      }
1193    
1194    closeFile(fThumbnail);
1195    return bResult;    
1196    } // extractAndCopyImage
1197                                        
1198
1199  /**
1200  * Seek to offset from beginning of file 
1201  *
1202  */
1203  protected boolean goToFileLocation(FlexXRandomAccessFile fFile, long nFilePos)
1204    {
1205    boolean bResult = true;
1206
1207    try
1208      {
1209      fFile.seek(nFilePos);
1210      }
1211      
1212    catch(IOException e)
1213      {
1214      printDiagnosticMessage("Error seeking to offset " + ": " + e.toString());
1215      bResult = false;
1216      }
1217      
1218    return bResult;
1219    } // goToFileLocation
1220  
1221    
1222    
1223  /**
1224  *
1225  *
1226  */
1227  protected boolean copyBytes(FlexXRandomAccessFile fFrom, 
1228                              FlexXRandomAccessFile fTo, 
1229                              int nCount)
1230    {
1231    boolean bDone        = false;
1232    boolean bReadAll     = false;
1233    int     nBytesToRead = 0;
1234    int     nRead        = -1;
1235    int     nBuffSize    = 512;
1236    byte    anData[]     = new byte[nBuffSize];    
1237    
1238    // nCount = -1 indicates that the remainder of the file
1239    // should be read
1240    if (nCount == -1)
1241      {
1242      bReadAll = true;
1243      }
1244
1245    // Read/write until nCount bytes, or end-of-file, or error
1246    while (true)
1247      {
1248      // Set the buffer size
1249      if ((bReadAll == false) && (nCount <= nBuffSize))
1250        {
1251        nBytesToRead = nCount;
1252        bDone = true;
1253        }
1254        
1255      else
1256        {
1257        nBytesToRead = nBuffSize;
1258        }
1259        
1260      // Read a block and write it to the "to" file
1261      try
1262        {
1263        nRead = fFrom.read(anData, 0, nBytesToRead);
1264        if (nRead == -1)
1265          {
1266          // No more data, end of file
1267          return true;
1268          }
1269        
1270        // Write to the output file unless in no-write mode
1271        if (fTo != null)
1272          {
1273          fTo.write(anData, 0, nRead);
1274          }
1275        
1276        if (bDone == true)
1277          {
1278          // All bytes transfered
1279          return true;
1280          }
1281        } // try
1282      
1283      catch(IOException e)
1284        {
1285        printDiagnosticMessage("Error reading/writing bytes " + ": " + e.toString());
1286        return false;
1287        }
1288      
1289      // Decrement the count of remaining bytes to transfer
1290      nCount -= nRead;
1291      } // while true
1292    } // copyBytes
1293  
1294  /**
1295  *
1296  *
1297  */
1298  protected boolean closeFile(FlexXRandomAccessFile fFile)
1299    {
1300    if (fFile == null)
1301      {
1302      return true;
1303      }
1304      
1305    try
1306      {
1307      fFile.close();
1308      }
1309      
1310    catch(IOException e)
1311      {
1312      printDiagnosticMessage("Error closing file " + ": " + e.toString());
1313      return false;
1314      }
1315    
1316    return true;
1317    } // closeFile
1318    
1319  
1320  /**
1321  *
1322  *
1323  */
1324  public Vector getMap(FlexXRandomAccessFile fInputFile)
1325    {
1326    Vector vImagePointer = new Vector();
1327    nAdditionalItems = 0;
1328    
1329    // Get the first 16 bytes of the file
1330    byte anData[] = readBytes(fInputFile, 16);
1331    if (anData == null)
1332      {
1333      return null;
1334      }
1335    
1336    // Get the pointer to the map
1337    int nMapPointer = getInt(anData, 4, 4);
1338    if (nMapPointer == 0)
1339      {
1340      return null;
1341      }
1342    
1343    // Get the byte size of the map
1344    int nMapSize = getInt(anData, 14, 2);
1345    if ((nMapSize == 0) || (nMapSize > 1000)) // Maximum size was arbitrarily selected.  
1346      {                                       // Concern is that for an illegal file this
1347      return null;                            // may get huge, causing memory problems.  
1348      }
1349    
1350    // Go to the map block
1351    if (goToFileLocation(fInputFile, nMapPointer) == false)      
1352      {
1353      return null;  
1354      }
1355        
1356    // Read the full map data block
1357    byte anMapData[] = readBytes(fInputFile, nMapSize); 
1358    if (anMapData == null)
1359      {
1360      return null;
1361      }
1362    
1363    // Get the count of named pointers
1364    int nNamedCount = getInt(anMapData, 28, 2);
1365    if (nNamedCount == 0)
1366      {
1367      return null;
1368      }
1369      
1370    nNamedCount += 1;
1371    int nNamedBaseIndex = 30;
1372    
1373    // Get each named pointer and its associated image block pointers
1374    int nItemOffset = nNamedBaseIndex; 
1375    for (int i=0; i<nNamedCount; i++)
1376      {
1377      // Get the name (4 bytes)
1378      byte abName[] = new byte[4];
1379      for (int j=0; j<4; j++)
1380        {
1381        abName[j] = (byte)anMapData[nItemOffset + j];
1382        }
1383      
1384      // Convert the name to a string
1385      String sName = new String(abName);
1386      
1387      // Get the count of additional items (2 bytes)
1388      nAdditionalItems = getInt(anMapData, nItemOffset + 4,2);
1389      
1390      // Get the offset to the image block pointer
1391      int nImageBlockPtr   = getInt(anMapData, nItemOffset + 6, 2);
1392      
1393      // Get the Image pointer
1394      int nImagePointer    = getInt(anMapData, nNamedBaseIndex + nImageBlockPtr + 2, 4);
1395      
1396      // Get the magic number (the last item doesnt have one)
1397      int nMagicNumber = -1;
1398      if (i < nNamedCount - 1)
1399        {
1400        nMagicNumber = getInt(anMapData, nNamedBaseIndex + nImageBlockPtr + 10, 2);
1401        }
1402        
1403      // Put the name and pointer in vector
1404      vImagePointer.addElement(new ImagePointer(sName, 
1405                                                  nImagePointer, 
1406                                                  0, 
1407                                                  nMagicNumber));
1408      
1409      // Get any additional pointers associated with the named image pointer
1410      if (nAdditionalItems > 0)
1411        {
1412        int nPtrOffset = 12;
1413        for (int k=0; k<nAdditionalItems; k++)
1414          {
1415          // Get the image pointer and magic number
1416          nImagePointer = getInt(anMapData, nNamedBaseIndex + nImageBlockPtr + nPtrOffset + 2, 4);  
1417          nMagicNumber  = getInt(anMapData, nNamedBaseIndex + nImageBlockPtr + nPtrOffset + 10, 2);
1418          
1419          // Add the previous name (these pointers are not named) and pointer to the vector
1420          vImagePointer.addElement(new ImagePointer(sName, 
1421                                                      nImagePointer, 
1422                                                      k+1, 
1423                                                      nMagicNumber));
1424      
1425          nPtrOffset += 12;
1426          }
1427        } // nAdditionalItems if
1428        
1429      // Go to next item
1430      nItemOffset += 8;
1431      } // for
1432    
1433    
1434    return vImagePointer;
1435    } // getMap
1436  
1437  /**
1438  *
1439  *
1440  */
1441  public int getInt(byte anData[], int nStartIndex, int nCount)
1442    {
1443    int nInt = 0;
1444    if ((nCount + nStartIndex) > anData.length)
1445      {
1446      return 0;
1447      }
1448      
1449    for (int i=nStartIndex; i<nStartIndex + nCount; i++)
1450      {
1451      nInt = nInt << 8;
1452      int nTemp = 0;
1453      nTemp = (nTemp | anData[i]) & 0xff;  
1454      nInt = nInt | nTemp;
1455      }    
1456    
1457    nInt = nInt & 0xffffffff;
1458    return nInt;
1459    } // getInt
1460  
1461  /**
1462  *
1463  *
1464  */
1465  protected void printMap(Vector vMap)
1466    {
1467    if ((vMap == null) || (vMap.size() == 0))
1468      {
1469      printDiagnosticMessage("No items found for map");
1470      return;
1471      }
1472      
1473    for (int i=0; i<vMap.size(); i++)
1474      {
1475      ImagePointer refImagePointer = (ImagePointer)vMap.elementAt(i);
1476      refImagePointer.printMapItem();
1477      }
1478    } // printMap
1479  
1480  
1481  /**
1482  *
1483  *
1484  */
1485  public int getWidth()
1486    {
1487    return nImageWidth;
1488    }
1489  
1490  /**
1491  *
1492  *
1493  */
1494  public int getHeight()
1495    {
1496    return nImageHeight;
1497    }
1498    
1499  /**
1500  *
1501  *
1502  */
1503  public int getXResolution()
1504    {
1505    return nImageXResolution;
1506    }
1507  
1508  /**
1509  *
1510  *
1511  */
1512  public int getYResolution()
1513    {
1514    return nImageYResolution;
1515    }
1516  
1517  /**
1518  *
1519  *
1520  */
1521  public long getFilesize()
1522    {
1523    return nFilesize;
1524    }
1525  
1526  /**
1527  *
1528  *
1529  */
1530  public String getType()
1531    {
1532    return sImageType;
1533    }
1534    
1535  /**
1536  *
1537  *
1538  */
1539  protected void printDiagnosticMessage(String sMsg)
1540    {
1541    if (bTest == false)
1542      {
1543      Diagnostic.trace(Diagnostic.APPSERVER_IMPORT, sMsg);      
1544      }
1545      
1546    else
1547      {
1548      System.out.println(sMsg);
1549      }
1550    }// printDiagnosticMessage
1551  
1552  } // FPOExtact
1553  
1554  
1555     
1556