// **********************************************************************
//
//
* * The RPF specification, MIL-STD-2411, has definitions for how frames * are to be laid out and found within a RPF directory. All RPF data * is supposed to lie under one RPF directory, and an A.TOC file, * describing all the files and their groupings, should be directly * within the RPF directory. That's why the RpfLayer needs a path to * a RPF directory - it's really looking for the A.TOC file, and * knows where to find it. It also needs a path to the RPF directory * because it needs to prepend that path to the paths to the files * that the A.TOC file knows about.
* * The A.TOC files that can be created with this MakeToc class can be * created to contain absolute frame paths. The MakeToc class can * take the paths to several RPF directories, and create a single * A.TOC file that preserves all of their current file paths. You * have to use alot of caution with this capability, however. These * A.TOCs containing absolute file paths will not work if the data is * moved to another machine, or if referenced by a machine with a * different type file system (i.e. Windows). They may not work for * other implementations of code that display RPF data - the code in * this package has been modified to test for absolute file names.
* * That said, absolute file names should be used instead of giving the * RpfLayer several RPF directories. The RpfTocHandler does much less * work when it is allowed to group coverages together to make bigger * areas.
* * This code was ported from C code provided in the original Mitre RPF * package that had limits to the number of frames that could make up * the areas. I'll be working to eliminate those limits, but I wanted * to get a working version of the code out there. I'm also planning * on modifying this class so that it can load the RpfTocHandler * directly, therefore eliminating the need for A.TOCs altogether when * there is more than one RPF directory.
*
* Usage: java com.bbn.openmap.layer.rpf.MakeToc (RPF dir path) (RPF dir path) ... ** This will create an A.TOC file in the current directory for the RPF * files in the RPF directory paths. Use: *
* java com.bbn.openmap.layer.rpf.MakeToc -help ** * for other options. * *
NOTE: Make sure that the RPF directories and their contents are in * upper case. Its a spec requirement, although with CD copies and * FTP downloads, the file name cases sometimes get switched. Use * com.bbn.openmap.layer.rpf.ChangeCase to modify the file name * cases.
* @see com.bbn.openmap.layer.rpf.ChangeCase */ public class MakeToc { /** * According to Dan Scholten's original code, this was 2 times the * max - changed from 30 on 6/17/94 to 200 for 81 JNC's in zone 1. * This might not be enough for world-wide coverage of larger * scale maps that are now available. This number may have to be * increased depending on how much data you need. */ public final static int DEFAULT_MAX_SIDE = 200; public final static double EPS = 0.01; public final static double EPS2 = 0.0001; /** Output file name of the A.TOC file. */ public final static String ATOC_FILENAME = "A.TOC"; /** The boundary edge frame length for groups. */ protected int maxSide = DEFAULT_MAX_SIDE; /** Flag to use relative frames paths - default is true. */ protected boolean relativeFramePaths = true; /** The producer name for the frame files. Default is DMAAC. */ protected String producer = "DMAAC"; protected ProgressSupport progressSupport; /** An internal representation of a Frame file. */ public class Frame { double left; double right; double top; double bottom; /* New DKS: for computing GEOREF #'s over polar region */ double swlat; double swlon; double h_interval; double v_interval; double h_resolution; double v_resolution; String scale; // length 12 char zone; boolean marked; int group; int x; int y; String filename; boolean cib; boolean cdted; public double EPS () { return (Math.abs(right - left) * MakeToc.EPS); }; public String toString() { StringBuffer s = new StringBuffer(); s.append("Frame - " + filename + "\n"); s.append(" zone = " + zone + "\n"); s.append(" marked = " + marked + "\n"); s.append(" scale = " + scale + "\n"); s.append(" group = " + group + "\n"); if (Debug.debugging("maketocframe")) { s.append(" top = " + top + "\n"); s.append(" bottom = " + bottom + "\n"); s.append(" left = " + left + "\n"); s.append(" right = " + right + "\n"); s.append(" h_interval = " + h_interval + "\n"); s.append(" v_interval = " + v_interval + "\n"); s.append(" h_resolution = " + h_resolution + "\n"); s.append(" v_resolution = " + v_resolution + "\n"); } return s.toString(); } } /** An internal representation of a boundary rectangle for frames. */ public class Group { double[] horiz_pos; double[] vert_pos; int left; int right; int top; int bottom; String scale; char zone; double h_interval; double v_interval; double h_resolution; double v_resolution; boolean cib; boolean cdted; public Group() { horiz_pos = new double[maxSide]; vert_pos = new double[maxSide]; } public String toString() { StringBuffer s = new StringBuffer(); s.append("Group - \n"); s.append(" zone = " + zone + "\n"); s.append(" scale = " + scale + "\n"); s.append(" left = " + left + "\n"); s.append(" right = " + right + "\n"); s.append(" top = " + top + "\n"); s.append(" bottom = " + bottom + "\n"); s.append(" is cdted = " + cdted + "\n"); s.append(" is cib = " + cib + "\n"); return s.toString(); } } public MakeToc() { progressSupport = new ProgressSupport(this); } /** * Create an A.TOC file. * @param argv The arguments should at least include a path to a * RPF file root directory. Other options can be found by using a * -help option. */ public static void main(String[] argv) { Debug.init(); boolean Dchum = false; ArgParser ap = new ArgParser("MakeToc"); ap.add("absolute", "Use absolute paths in A.TOC - Use for multiple RPF Directories"); ap.add("boundary", "Maximum frames on a boundary edge (Default 200)", 1); ap.add("dchum", "DCHUM files are included."); ap.add("log", "Pathname of log file to list A.TOC creation output.", 1); ap.add("output", "Path to directory to place A.TOC file. (Default is current directory)", 1); ap.add("producer", "The producer of the frames (Default DMAAC). Five letter code.", 1); ap.add("verbose", "Print out progress"); ap.add("extraverbose", "Print out ALL progress"); ap.add("nw", "Don't put up swing progress window (Use this if you are getting weird exceptions)"); ap.add("paths", "Space separated paths to RPF directory or directories. Should be last. If more than one directory is listed, then absolute paths are used in the A.TOC file.", ArgParser.TO_END); if (!ap.parse(argv)) { ap.printUsage(); System.exit(0); } String outputFile = "." + File.separator + RpfTocHandler.RPF_TOC_FILE_NAME; String arg[]; arg = ap.getArgValues("output"); if (arg != null) { outputFile = arg[0] + File.separator + RpfTocHandler.RPF_TOC_FILE_NAME; } arg = ap.getArgValues("log"); if (arg != null) { String logfile = arg[0]; Debug.directOutput(logfile, false, true); Debug.output("MakeToc: Creating log at " + logfile + " at " + java.util.Calendar.getInstance().getTime()); } arg = ap.getArgValues("dchum"); if (arg != null) { Dchum = true; } arg = ap.getArgValues("verbose"); if (arg != null) { Debug.put("maketoc"); } arg = ap.getArgValues("extraverbose"); if (arg != null) { Debug.put("maketoc"); Debug.put("maketocdetail"); } String[] paths = null; arg = ap.getArgValues("paths"); if (arg != null) { paths = arg; } else { paths = ap.getRest(); } if (paths == null || paths.length == 0) { Debug.output("MakeToc: need a path to start searching for RPF frames."); System.exit(0); } MakeToc mt = new MakeToc(); // If the -nw argument was not used, add a progress gauge. arg = ap.getArgValues("nw"); if (arg == null) { try { mt.addProgressListener(new com.bbn.openmap.gui.ProgressListenerGauge("RPF A.TOC File Creation")); } catch (RuntimeException re) { } } boolean argFlagged = false; arg = ap.getArgValues("absolute"); if (arg != null) { argFlagged = true; } arg = ap.getArgValues("producer"); if (arg != null) { mt.setProducer(arg[0]); } if (paths.length > 1 || argFlagged) { Debug.output("MakeToc: creating A.TOC with absolute path names."); mt.setRelativeFramePaths(false); } arg = ap.getArgValues("boundary"); int max_side = DEFAULT_MAX_SIDE; if (arg != null) { try { max_side = Integer.parseInt(arg[0]); if (max_side <= DEFAULT_MAX_SIDE) { Debug.output("MakeToc: Boundary number specified (" + max_side + ") is too small. Using default of 200."); max_side = DEFAULT_MAX_SIDE; } } catch (NumberFormatException nfe) { Debug.output("MakeToc: Tried to pass a bogus integer (" + arg[0] + ") as a boundary limit. Using default of 200."); max_side = DEFAULT_MAX_SIDE; } } mt.setMaxSide(max_side); mt.fireProgressUpdate(ProgressEvent.START, "Searching for RPF frames", 0, 100); paths = mt.searchForRpfFiles(paths); try { mt.create(paths, outputFile, Dchum); } catch (MakeTocException mte) { Debug.error("Problem creating A.TOC file: \n" + mte.getMessage()); } System.exit(0); } /** * Create a A.TOC file specificed by the frame file list, at the * location specified. * @param rpfFilePaths An array of all RPF Frame file paths. If * these paths are relative, the MakeToc class should be set for * that. * @param outputFile the complete pathname to an A.TOC file to be * written. * @exception MakeTocException if anything goes wrong. */ public void create(String[] rpfFilePaths, String outputFile) throws MakeTocException { create(rpfFilePaths, outputFile, false); } /** * Create a A.TOC file specificed by the frame file list, at the * location specified. * @param rpfFilePaths An array of all RPF Frame file paths. If * these paths are relative, the MakeToc class should be set for * that. * @param outputFile the complete pathname to an A.TOC file to be * written. * @param dchum If dchum is present, all frames get placed in * their own group. False is default. Dchum are replacement subframes. * @exception MakeTocException if anything goes wrong. */ public void create(String[] rpfFilePaths, String outputFile, boolean dchum) throws MakeTocException { RpfHeader head = new RpfHeader(); Vector frames = new Vector(rpfFilePaths.length); Vector groups = new Vector(); fireProgressUpdate(ProgressEvent.UPDATE, "Organizing frames", 0, 100); organizeFrames(rpfFilePaths, head, frames); if (head.standardNumber == null) { throw new MakeTocException("MakeToc: No RPF frames found."); } groupFrames(frames, groups, dchum); fireProgressUpdate(ProgressEvent.UPDATE, "Writing A.TOC file", 100, 100); writeTOCFile(outputFile, head, frames, groups); fireProgressUpdate(ProgressEvent.DONE, "A.TOC file complete", 100, 100); } /** * Look for RPF frame files, given a bunch of places to start * looking. The output of this can be passed to the create method. * @param startDirs Directory paths. * @return an array of strings representing path names to RPF * frame files. */ public String[] searchForRpfFiles(String[] startDirs) { RpfFileSearch search = new RpfFileSearch(); for (int i = 0; i < startDirs.length; i++) { search.handleEntry(startDirs[i]); } return search.getFiles(); } /** * Set whether to use relative frame paths in the A.TOC file. */ public void setRelativeFramePaths(boolean setting) { relativeFramePaths = setting; } public boolean getRelativeFramePaths() { return relativeFramePaths; } /** * Set the 5 letter producer code for the frames. If you didn't * make the frames, they DMA probably did, so the default is * applicable - DMAAC. There are a bunch of accepted codes in the * MIL-STD-2411 for producers. */ public void setProducer(String setting) { if (setting.length() != 5) { if (setting.length() >= 5) { producer = setting.substring(0, 5); } else { producer = setting + createPadding(5 - setting.length(), false); } } else { producer = setting; } } /** Get the producer code currently set.*/ public String getProducer() { return producer; } /** * Set the Maximum number of frames along a group boundary edge. Don't * change this after starting to group the frames. */ protected void setMaxSide(int set) { maxSide = set; } /** * Get the Maximum number of frames along a group boundary edge. */ protected int getMaxSide() { return maxSide; } /** A little function to tell of one edge is near another. */ protected boolean near(double a, double b, double eps) { return (Math.abs(a-b) < eps); /* EPS was 0.0001 */ } /** * Get all the frame paths, and sort through them. This method * sets up the frames vector and loads each Frame with it's * attributes, so it can be grouped with its neighbors. * @param framePaths the array of RPF file paths. * @param head an RpfHeader object to load with production * information, that will be put into the A.TOC file. * @param frames the frame vector to load. */ public void organizeFrames(String[] framePaths, RpfHeader head, Vector frames) { int tail; int i, j; boolean done; /* New, DKS */ boolean Cib = false; /* CIB data flag: 1:I1(10M); 2:I2(5M) */ boolean Cdted = false; /* CDTED data flag: 1: DT1(100M) */ boolean isoverview = false; boolean islegend = false; Frame frame; RpfFileSections.RpfLocationSection loc; RpfFileSections.RpfCoverageSection coverage; Debug.message("maketoc", "MakeToc.organizeFrames: *** initial look at frames ***"); /* # of frames = # of pathname records = #files */ int nFrames = framePaths.length; if (Debug.debugging("maketoc")) { Debug.output("Number of frames: " + nFrames); } /* for each frame file */ for (i = 0; i < nFrames; i++) { isoverview = false; islegend = false; String framePath = framePaths[i]; if (Debug.debugging("maketoc")) { Debug.output("MakeToc: frame number " + i + ", " + framePath); } try { BinaryFile binFile = new BinaryBufferedFile(framePath); // binFile = new BinaryFile(framePath); RpfFileSections rfs = new RpfFileSections(); binFile.seek(0); if (!head.read(binFile)) { // Not a RPF Frame file Debug.error("MakeToc: " + framePath + " is not a RPF file - ignoring"); continue; } binFile.seek(head.locationSectionLocation); rfs.parse(binFile); coverage = rfs.parseCoverageSection(binFile); if (coverage == null) { Debug.error("MakeToc: error reading coverage section for " + framePath + ", (file " + i + ") skipping"); binFile.close(); continue; } if (Debug.debugging("maketocframedetail")) { Debug.output("MakeToc.organizeFrames: coverage section for " + framePath + ", " + coverage); } binFile.close(); binFile = null; } catch (FileNotFoundException e) { Debug.error("MakeToc: " + framePath + " not found, being ignored."); continue; } catch (IOException ioe) { Debug.error("MakeToc: File IO Error during read of: " + framePath + "! Being ignored. \n" + ioe); continue; } frame = new Frame(); frames.add(frame); frame.filename = framePath; // This will be the actual file name, without parental path. String framename; tail = frame.filename.lastIndexOf(File.separatorChar); if (tail == -1) { framename = frame.filename ; } else { framename = frame.filename.substring(++tail); } if (framename.length() != 12) { Debug.error( "filename must be 12 chars long - " + framename); return; } // 9 is the character after the period. isoverview = (framename.charAt(9) == 'O'); if (!isoverview) { islegend = framename.regionMatches(true, 9, "LG", 0, 2); } // Check and see of the file thinks it's name is the same // as it acutally is. If they differ, rule in favor of // what the frame thinks it is. // Let's just be passive here, and name it to whatever it // is. If we found the frame, then we'll find it later, // too. -DFD // if (!framename.equals(head.filename)) { /* DKS */ // File file = new File(frame.filename); // File newFile = new File(frame.filename.substring(0, tail), // head.filename); // file.renameTo(newFile); // framename = head.filename; // Debug.output("WARNING: File \"" + framename + // "\" doesn't match internal name \"" + head.filename + // "\" - Fixed."); // } isoverview = false; islegend = false; String padding = null; String seriesCode = head.filename.substring(9, 11); RpfProductInfo rpi = RpfProductInfo.get(seriesCode); String scaleString = rpi.scaleString; if (rpi == RpfConstants.UK) { Debug.output("MakeToc: " + frame.filename + " unknown map type " + seriesCode + " - ignoring."); continue; } else if (rpi.scale == RpfConstants.Various) { // need to figure out how to consult the frame for what it is. // RpfAttributes.chartSeriesCode might have something to base it off. // GNC = GN, JNC = JN, ONC = ON, TPC = TP, JOG = 15, TLM50 = V7, // But I'm not sure about the others. For now, prompt for scale. scaleString = promptForScale("What is the scale for " + frame.filename + "? (Answer should look like: 1:XXX,XXX)"); if (scaleString == null || scaleString.length() == 0) { Debug.error("Bad input for scale for " + frame.filename + ", skipping."); continue; } } if (rpi.dataType.equalsIgnoreCase(RpfConstants.CIB)) { frame.cib = true; } else if (rpi.dataType.equalsIgnoreCase(RpfConstants.CDTED)) { frame.cdted = true; } // else do nothing for CADRG // Set the string to length 15 if (scaleString.length() < 15) { padding = createPadding(15 - scaleString.length(), false); scaleString = scaleString + padding; } else if (scaleString.length() > 15) { scaleString = scaleString.substring(0, 15); } frame.scale = scaleString; frame.zone = head.filename.charAt(11); if (isoverview) { coverage.nwlat = coverage.nelat = coverage.nwlon = coverage.swlon = coverage.swlat = coverage.selat = coverage.nelon = coverage.selon = 0; coverage.latInterval = coverage.lonInterval = coverage.nsVertRes = coverage.ewHorRes = 0; } if (islegend) { coverage.nwlat = coverage.nelat = coverage.nwlon = coverage.swlon = coverage.swlat = coverage.selat = coverage.nelon = coverage.selon = 0; coverage.latInterval = coverage.lonInterval = coverage.nsVertRes = coverage.ewHorRes = 0; } /* PBF 6-18-94 check for rectangular coverage or polar frame */ if (frame.zone == '9' || frame.zone == 'J') { /* Polar. Convert boundary from lat-long degrees to pixels */ /* DKS 1/95: North pole: "9" code */ if (frame.zone == '9') { if (Debug.debugging("maketoc")) Debug.output("Processing NORTH pole") ; frame.left = (90.0 - coverage.nwlat) * Math.sin(coverage.nwlon * Math.PI / 180.0) / coverage.latInterval; frame.right = (90.0 - coverage.selat) * Math.sin(coverage.selon * Math.PI / 180.0) / coverage.latInterval; frame.top = -1 * (90.0 - coverage.nwlat) * Math.cos(coverage.nwlon * Math.PI / 180.0) / coverage.latInterval; frame.bottom = -1 * (90.0 - coverage.selat) * Math.cos(coverage.selon * Math.PI / 180.0) / coverage.latInterval; } else { /* DKS 1/95: South pole: "J" code */ if (Debug.debugging("maketoc")) Debug.output("Processing SOUTH pole"); frame.left = (90.0 + coverage.nwlat) * Math.sin(coverage.nwlon * Math.PI / 180.0) / coverage.latInterval; frame.right = (90.0 + coverage.selat) * Math.sin(coverage.selon * Math.PI / 180.0) / coverage.latInterval; frame.top = (90.0 + coverage.nwlat) * Math.cos(coverage.nwlon * Math.PI / 180.0) / coverage.latInterval; frame.bottom = (90.0 + coverage.selat) * Math.cos(coverage.selon * Math.PI / 180.0) / coverage.latInterval; } /* if South pole */ /* DKS 8/1/94: Added for GEOREF calc later */ frame.swlat = coverage.swlat; frame.swlon = coverage.swlon; if (Debug.debugging("maketoc")) { Debug.output("MakeToc: " + frame.filename + " is a Polar frame"); } /* if Debug.debugging("maketoc") */ } else { frame.left = coverage.nwlon; frame.right = coverage.selon; /* NEW, DKS 6/94. Correct for frame straddling 180 deg. */ if (coverage.selon < coverage.nwlon) { frame.right = 180.0; } frame.top = coverage.nwlat; frame.bottom = coverage.selat; } frame.h_interval = coverage.lonInterval; frame.v_interval = coverage.latInterval; frame.h_resolution = coverage.ewHorRes; frame.v_resolution = coverage.nsVertRes; frame.marked = false; if (Debug.debugging("maketocframedetail")) { Debug.output("MakeToc: nw_lon = " + coverage.nwlon + ", se_lon = " + coverage.selon + "\n nwlat = " + coverage.nwlat + ", selat = " + coverage.selat + "\n NEW: swlat = " + coverage.swlat + ", swlon = " + coverage.swlon + "\n vert_interval = " + coverage.latInterval + ", horiz_interval = " + coverage.lonInterval + "\n vertical resolution = " + coverage.nsVertRes + ", horizontal resolution = " + coverage.ewHorRes + "\n left = " + frame.left + ", right = " + frame.right + "\n top = " + frame.top + ", bottom = " + frame.bottom + "\n"); } } /* for i: each input frame file */ } /** * Prompt for input. */ public String promptForScale(String query) { try { String answer = null; System.out.println(query); InputStreamReader isr = new InputStreamReader(System.in); BufferedReader bufr = new BufferedReader(isr); answer = bufr.readLine(); return answer; } catch (IOException ioe) { Debug.error("MakeToc: IOException trying to get an answer from you. Dang."); return null; } } /** * Create and write out an A.TOC file. * @param filename the output filename. * @param head the RpfHeader containing header information. * @param frames the frame Vector. * @param groups the file groups Vector. */ public void writeTOCFile(String filename, RpfHeader head, Vector frames, Vector groups) throws MakeTocException { short us; int ui; int i, j, tail; /* DKS changed from left, right for polar zone: new left_bottom longit. */ double left_b, left_t, right_b, right_t, top, bottom; double xleft, xright, ytop, ybottom; /* !! To be filled in later */ int TOC_Nitf_hdr_size = 0; /* ?? Nitf header size for output TOC */ int Loc_sec_len; /* Location section length */ int Bound_tbl_len; /* Boundary rectangle table length */ int Frame_hdr_len = 13; /* Frame index header length */ int Frame_index_rec_len = 33; /* Frame index record length (was 37) */ int Frame_sec_len ; /* Frame section length */ RandomAccessFile fout = null; int groupCount = groups.size(); int nFrames = frames.size(); /* cumulative pathname positions */ int[] pathname_pos = new int[nFrames]; /* List of pathnames: directories */ String[] direct = new String[nFrames]; /* Allocations for uniq directories */ int[] uniq_dir_ptr = new int[nFrames]; /* index from filename to uniq direct. */ int[] uniq_dir_pos = new int[nFrames]; /* position of direct. name in file */ /* list of direct. names */ String[] uniq_dir = new String[nFrames]; String georef = "AAAAAA" ; /* GEOREF # */ Frame frame; Group group; // Right now, just write the new file locally. try { fout = new RandomAccessFile(filename, "rw"); /* WRITE TOC : */ if (Debug.debugging("maketoc")) { Debug.output("MakeToc: *** writing TOC ***\n at: " + filename) ; } /* HEADER SECTION */ if (Debug.debugging("maketoc")) { Debug.output("MakeToc: *** writing header section ***"); } String charString; char[] nt = new char[1]; nt[0] = '\0'; /* DKS. Can't write structure because of pad bytes */ /* fwrite(&head, sizeof(head), 1, fout); */ fout.writeBoolean(head.endian); // Big Endian - should match head.endian fout.writeShort(RpfHeader.HEADER_SECTION_LENGTH); fout.writeBytes(" A.TOC"); // has to be padded. fout.writeByte(head.neww); fout.writeBytes(head.standardNumber); if (head.standardNumber.length() < 15) { fout.writeBytes(createPadding(15 - head.standardNumber.length(), false)); } fout.writeBytes(head.standardDate); if (head.standardDate.length() < 8) { fout.writeBytes(createPadding(8 - head.standardDate.length(), false)); } // All this trouble just for a silly character. char[] charArray = new char[1]; charArray[0] = head.classification; charString = new String(charArray); fout.writeBytes(charString); Debug.message("maketoc", "MakeToc: writing country(" + head.country + ") and release(" + head.release + ")"); fout.writeBytes(head.country); fout.writeBytes(head.release); /* New, DKS. no longer head.loc_sec_phys_loc. Always write 48. */ /* DFD - This isn't true, but since we don't care about NITF formatting, it may be. Just write out where we are. */ int location_section_location = (int)fout.getFilePointer() + 4; fout.writeInt(location_section_location); if (Debug.debugging("maketoc")) { Debug.output("MakeToc: location section location is : " + location_section_location); } if (Debug.debugging("maketoc")) { Debug.output("MakeToc: *** writing location section ***"); } /* LOCATION SECTION */ int Loc_hdr_len = 14; /* Location section header length */ int Loc_sec_comp_len = 10; /* Location section component length */ /* 14 + 4 * 10 = 54 */ Loc_sec_len = Loc_hdr_len + (RpfFileSections.TOC_LOCATION_KEY * Loc_sec_comp_len); fout.writeShort(Loc_sec_len); /* compon. loc tbl offset: location section hdr length */ fout.writeInt(Loc_hdr_len); /* # records in location section: 4 */ fout.writeShort(RpfFileSections.TOC_LOCATION_KEY); /* component location record length: 10 */ fout.writeShort(Loc_sec_comp_len); if (Debug.debugging("maketoc")) { Debug.output("MakeToc:\n location section length: " + Loc_sec_len + "\n location header length: " + Loc_hdr_len + "\n number of location records: " + RpfFileSections.TOC_LOCATION_KEY + "\n location section comp length: " + Loc_sec_comp_len); } /* compon. aggregate len: unknown here. Fill in after doing all else.*/ /* location component aggregate length file location */ long agg_loc = fout.getFilePointer(); /* save for later */ fout.writeInt(0); // place holder. /* Begin: location section, component location table */ int Bound_hdr_len = 8; /* Boundary section header length */ int Bound_rec_len = 132; /* Boundary record length */ /* Boundary section length */ int Bound_sec_len = Bound_hdr_len + (groupCount * Bound_rec_len); /* Compute frame section length, for later */ pathname_pos[0] = 0; /* cum. offset */ int uniq_dir_cnt = 0; /* # of unique directory paths. */ // Looking for the directory name for each file. for (i=0; i