BSA(String filePath, boolean load) throws FileNotFoundException, IOException, BadParameter { this.filePath = filePath; in.openFile(filePath); if (!in.extractString(0, 3).equals("BSA") || in.extractInt(1, 4) != 104) { throw new BadParameter("Was not a BSA file of version 104: " + filePath); } offset = in.extractInt(0, 4); archiveFlags = new LFlags(in.extract(0, 4)); folderCount = in.extractInt(0, 4); folders = new HashMap<>(folderCount); fileCount = in.extractInt(0, 4); folderNameLength = in.extractInt(0, 4); fileNameLength = in.extractInt(0, 4); fileFlags = new LFlags(in.extract(0, 4)); if (SPGlobal.debugBSAimport && SPGlobal.logging()) { SPGlobal.logSpecial(LogTypes.BSA, header, "|==================>"); SPGlobal.logSpecial(LogTypes.BSA, header, "| Imported " + filePath); SPGlobal.logSpecial( LogTypes.BSA, header, "| Offset " + offset + ", archiveFlags: " + archiveFlags); SPGlobal.logSpecial( LogTypes.BSA, header, "| hasDirectoryNames: " + archiveFlags.get(0) + ", hasFileNames: " + archiveFlags.get(1) + ", compressed: " + archiveFlags.get(2)); SPGlobal.logSpecial( LogTypes.BSA, header, "| FolderCount: " + Ln.prettyPrintHex(folderCount) + ", FileCount: " + Ln.prettyPrintHex(fileCount)); SPGlobal.logSpecial( LogTypes.BSA, header, "| totalFolderNameLength: " + Ln.prettyPrintHex(folderNameLength) + ", totalFileNameLength: " + Ln.prettyPrintHex(fileNameLength)); SPGlobal.logSpecial(LogTypes.BSA, header, "| fileFlags: " + fileFlags.toString()); SPGlobal.logSpecial(LogTypes.BSA, header, "|==================>"); } if (load) { loadFolders(); } }
/** * @param filePath filepath to query for and retrieve. * @return ShrinkArray of the raw data from the BSA of the file specified, already decompressed if * applicable; Empty ShrinkArray if the file did not exist. * @throws IOException * @throws DataFormatException */ public LShrinkArray getFile(String filePath) throws IOException, DataFormatException { BSAFileRef ref; if ((ref = getFileRef(filePath)) != null) { in.pos(getFileLocation(ref)); LShrinkArray out = new LShrinkArray(in.extract(0, ref.size)); trimName(out); if (isCompressed(ref)) { out = out.correctForCompression(); } return out; } return new LShrinkArray(new byte[0]); }
final void loadFolders() { if (loaded) { return; } loaded = true; if (SPGlobal.logging()) { SPGlobal.logSpecial(LogTypes.BSA, header, "|============================================"); SPGlobal.logSpecial(LogTypes.BSA, header, "|============ Loading " + this + " ============"); SPGlobal.logSpecial(LogTypes.BSA, header, "|============================================"); } try { String fileName; int fileCounter = 0; in.pos(offset); LShrinkArray folderData = new LShrinkArray(in.extract(0, folderCount * 16)); posAtFilenames(); LShrinkArray fileNames = new LShrinkArray(in.extract(0, fileNameLength)); for (int i = 0; i < folderCount; i++) { BSAFolder folder = new BSAFolder(); folderData.skip(8); // Skip Hash folder.setFileCount(folderData.extractInt(4)); folder.dataPos = folderData.extractInt(4); posAtFolder(folder); folder.name = in.extractString(0, in.read() - 1) + "\\"; folder.name = folder.name.toUpperCase(); in.skip(1); folders.put(folder.name, folder); if (SPGlobal.debugBSAimport && SPGlobal.logging()) { SPGlobal.logSpecial(LogTypes.BSA, header, "Loaded folder: " + folder.name); } for (int j = 0; j < folder.fileCount; j++) { BSAFileRef f = new BSAFileRef(); f.size = in.extractInt(8, 3); // Skip Hash LFlags sizeFlag = new LFlags(in.extract(1)); f.flippedCompression = sizeFlag.get(6); f.dataOffset = in.extractLong(0, 4); fileName = fileNames.extractString(); folder.files.put(fileName.toUpperCase(), f); if (SPGlobal.logging()) { SPGlobal.logSpecial( LogTypes.BSA, header, " " + fileName + ", size: " + Ln.prettyPrintHex(f.size) + ", offset: " + Ln.prettyPrintHex(f.dataOffset)); fileCounter++; } } } if (SPGlobal.logging()) { if (SPGlobal.debugBSAimport) { SPGlobal.logSpecial(LogTypes.BSA, header, "Loaded " + fileCounter + " files."); } SPGlobal.logSpecial(LogTypes.BSA, header, "Loaded BSA: " + getFilePath()); } } catch (Exception e) { SPGlobal.logException(e); SPGlobal.logError("BSA", "Skipped BSA " + this); bad = true; } }