NOTICE: This version of the NSF Unidata web site (archive.unidata.ucar.edu) is no longer being updated.
Current content can be found at unidata.ucar.edu.
To learn about what's going on, see About the Archive Site.
I'm working on a FitsForm.save() method and in the process I wrote a cross-checking program which contains the following code: public Data read(String name) throws BadFormException, IOException, VisADException { Form form; form = guessFormFromName(name); if (form != null) { try { Data d = form.open(name); return d; } catch (Exception e) { form = null; } } try { Data d = new Plain().open(name); return d; } catch (Exception e) { } try { Data d = new FitsForm().open(name); return d; } catch (Exception e) { } throw new VisADException("Couldn't read \"" + name + "\""); } public Form guessFormFromName(String name) { if (name.endsWith(".Z")) { name = name.substring(0, name.length() - 2); } else if (name.endsWith(".gz")) { name = name.substring(0, name.length() - 3); } if (name.endsWith(".nc")) { return new Plain(); } if (name.endsWith(".fits")) { return new FitsForm(); } return null; } (Yes, I know there are better ways to write this, but it's a bloody debugging script, not the ceiling of the Sistine Chapel) It'd sure be nice to push the logic from guessFormFromName() into the individual Form classes and augment that with code which recognizes the file type based on the first block. For example, FITS files always start with "SIMPLE = ", GIF files always start with "GIF87a" or "GIF89a", etc. Could we maybe add these methods to FormNode (I *hate* the method name but couldn't come up with anything better): public abstract boolean isThisType(String name) Returns true if this file name looks like it might be associated with a file of this type. Note that the file associated with this name may still be of this type, even though this function returns false. public abstract boolean isThisType(byte[] block) Returns true if this 512-byte block appears to be the first block of a file of this type. I think something like this would greatly speed up opening arbitrary files. Given the above changes, my test-jacket (and the Repository class) could be implemented like this: constructor { // build a list of all forms } public Data save(String name) { // make a copy of the form list // build sublist of all forms which return true for isThisType(name) if (sublist.length == 1) { // try to read this file try { Data d = sublist[0].open(name); } catch (Exception e) { } // didn't work; throw out this form copiedList = remove(copiedList, sublist); } else { // multiple matches for this filename; check magic for each one Data d = checkMagic(sublist, name); if (d != null) { return d; } } // try to open files whose magic number matches the file type Data d = checkMagic(copiedFile); if (d != null) { return d; } // for each entry remaining in the copiedList, try to read it in // and return the resulting Data object if it succeeds } private Data checkMagic(Form[] list, String name) { byte[] block = first 512 bytes in "name" for each entry in the list { if (entry.isThisType(block)) { try { Data d = entry.open(name); return d; } catch (Exception e) { // add entry to the list of forms that were tried triedForms.add(entry); } } } // remove the failed forms from the copied list copiedList = remove(copiedList, triedForms); }
visad
archives: