/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.apps.vmware.disk.descriptor; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.io.Reader; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.apache.log4j.Logger; import org.jnode.apps.vmware.disk.ExtentDeclaration; import org.jnode.apps.vmware.disk.IOUtils; import org.jnode.apps.vmware.disk.IOUtils.KeyValue; import org.jnode.apps.vmware.disk.extent.Access; import org.jnode.apps.vmware.disk.extent.Extent; import org.jnode.apps.vmware.disk.extent.ExtentType; import org.jnode.apps.vmware.disk.handler.FileDescriptor; import org.jnode.apps.vmware.disk.handler.UnsupportedFormatException; import org.jnode.util.ByteBufferInputStream; /** * Wrote from the 'Virtual Disk Format 1.0' specifications (from VMWare). * * @author Fabien DUMINY (fduminy at jnode dot org) * */ public abstract class DescriptorRW { private static final Logger LOG = Logger.getLogger(DescriptorRW.class); private static final String VERSION = "version"; private static final String CID = "CID"; private static final String PARENT_CID = "parentCID"; private static final String CREATE_TYPE = "createType"; private static final String DDB = "ddb"; private static final String ADAPTER_TYPE = "ddb.adapterType"; private static final String SECTORS = "ddb.geometry.sectors"; private static final String HEADS = "ddb.geometry.heads"; private static final String CYLINDERS = "ddb.geometry.cylinders"; /** * * @param file * @param firstSector * @param nbSectors * @return * @throws IOException * @throws UnsupportedFormatException */ public Descriptor read(File file, int firstSector, int nbSectors) throws IOException, UnsupportedFormatException { RandomAccessFile raf = null; BufferedReader br = null; try { raf = new RandomAccessFile(file, "r"); ByteBuffer bb = IOUtils.getSectorsByteBuffer(raf, firstSector, nbSectors); Reader r = new InputStreamReader(new ByteBufferInputStream(bb)); br = new BufferedReader(r); Header header = readHeader(br); List<String> extentDecls = new ArrayList<String>(); String lastLine = readExtents(br, extentDecls); DiskDatabase diskDatabase = readDiskDatabase(br, lastLine); List<Extent> extents = new ArrayList<Extent>(extentDecls.size()); ExtentDeclaration mainExtentDecl = null; for (String decl : extentDecls) { ExtentDeclaration extentDecl = readExtentDeclaration(decl, file); if (extentDecl.isMainExtent()) { mainExtentDecl = extentDecl; } else { FileDescriptor fileDescriptor = IOUtils.readFileDescriptor(extentDecl.getExtentFile()); Extent extent = createExtent(fileDescriptor, extentDecl); extents.add(extent); } } Descriptor desc = new Descriptor(file, header, extents, diskDatabase); Extent mainExtent = createMainExtent(desc, mainExtentDecl); extents.add(0, mainExtent); return desc; } finally { if (br != null) { br.close(); } if (raf != null) { raf.close(); } } } protected DiskDatabase readDiskDatabase(BufferedReader br, String lastLine) throws IOException { DiskDatabase ddb = new DiskDatabase(); Map<String, String> values = IOUtils.readValuesMap(lastLine, br, true, ADAPTER_TYPE, SECTORS, HEADS, CYLINDERS); String value = values.get(ADAPTER_TYPE); ddb.setAdapterType(AdapterType.valueOf(value)); value = values.get(SECTORS); ddb.setSectors(Integer.valueOf(value)); value = values.get(HEADS); ddb.setHeads(Integer.valueOf(value)); value = values.get(CYLINDERS); ddb.setCylinders(Integer.valueOf(value)); return ddb; } protected String readExtents(BufferedReader br, List<String> extentDecls) throws IOException, UnsupportedFormatException { String line; while (((line = IOUtils.readLine(br)) != null) && !line.startsWith(DDB)) { extentDecls.add(line); } return line; } protected ExtentDeclaration readExtentDeclaration(String line, File mainFile) { StringTokenizer st = new StringTokenizer(line, " ", false); final Access access = Access.valueOf(st.nextToken()); final long sizeInSectors = Long.valueOf(st.nextToken()); final ExtentType extentType = ExtentType.valueOf(st.nextToken()); final String fileName = IOUtils.removeQuotes(st.nextToken()); long offset = 0L; if (st.hasMoreTokens()) { offset = Long.valueOf(st.nextToken()); } return IOUtils.createExtentDeclaration(mainFile, fileName, access, sizeInSectors, extentType, offset); } protected Header readHeader(BufferedReader reader) throws IOException, UnsupportedFormatException { Header header = new Header(); LOG.debug("trying to read VERSION"); KeyValue keyValue = IOUtils.readValue(reader, null, VERSION, false); if (!"1".equals(keyValue.getValue())) { throw new UnsupportedFormatException("expected version 1 (found:" + keyValue.getValue() + ")"); } header.setVersion(keyValue.getValue()); keyValue = IOUtils.readValue(reader, keyValue, CID, false); header.setContentID(Long.valueOf(keyValue.getValue(), 16)); keyValue = IOUtils.readValue(reader, keyValue, PARENT_CID, false); header.setParentContentID(Long.parseLong(keyValue.getValue(), 16)); keyValue = IOUtils.readValue(reader, keyValue, CREATE_TYPE, true); header.setCreateType(CreateType.valueOf(keyValue.getValue())); return header; } protected abstract Extent createMainExtent(Descriptor desc, ExtentDeclaration mainExtentDecl) throws IOException, UnsupportedFormatException; protected abstract Extent createExtent(FileDescriptor fileDescriptor, ExtentDeclaration extentDecl) throws IOException, UnsupportedFormatException; }