UPS extends Patcher { @Override public void apply(boolean ignoreChecksum) throws PatchException, IOException { if (patchFile.length() < 18) { throw new PatchException(context.getString(R.string.notify_error_patch_corrupted)); } BufferedInputStream patchStream = null; BufferedInputStream romStream = null; BufferedOutputStream outputStream = null; UpsCrc upsCrc; try { if (!checkMagic(patchFile)) throw new PatchException(context.getString(R.string.notify_error_not_ups_patch)); upsCrc = readUpsCrc(context, patchFile); if (upsCrc.getPatchFileCRC() != upsCrc.getRealPatchCRC()) throw new PatchException(context.getString(R.string.notify_error_patch_corrupted)); patchStream = new BufferedInputStream(new FileInputStream(patchFile)); long patchPos = 0; for (int i = 0; i < 4; i++) { patchStream.read(); } patchPos += 4; Pair p; p = decode(patchStream); long xSize = p.getValue(); patchPos += p.getSize(); p = decode(patchStream); long ySize = p.getValue(); patchPos += p.getSize(); long realRomCrc = FileUtils.checksumCRC32(romFile); if (romFile.length() == xSize && realRomCrc == upsCrc.getInputFileCRC()) { } else if (romFile.length() == ySize && realRomCrc == upsCrc.getOutputFileCRC()) { long tmp = xSize; xSize = ySize; ySize = tmp; upsCrc.swapInOut(); } else { if (!ignoreChecksum) { throw new IOException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); } } romStream = new BufferedInputStream(new FileInputStream(romFile)); outputStream = new BufferedOutputStream(new FileOutputStream(outputFile)); long outPos = 0; int x, y; long offset = 0; while (patchPos < patchFile.length() - 12) { p = decode(patchStream); offset += p.getValue(); patchPos += p.getSize(); if (offset > ySize) continue; Utils.INSTANCE.copy(romStream, outputStream, offset - outPos); outPos += offset - outPos; for (long i = offset; i < ySize; i++) { x = patchStream.read(); patchPos++; offset++; if (x == 0x00) break; y = i < xSize ? romStream.read() : 0x00; outputStream.write(x ^ y); outPos++; } } Utils.INSTANCE.copy(romStream, outputStream, ySize - outPos); } finally { IOUtils.closeQuietly(patchStream); IOUtils.closeQuietly(romStream); IOUtils.closeQuietly(outputStream); } if (!ignoreChecksum) { long realOutCrc = FileUtils.checksumCRC32(outputFile); if (realOutCrc != upsCrc.getOutputFileCRC()) throw new PatchException(context.getString(R.string.notify_error_wrong_checksum_after_patching)); } } UPS(Context context, File patch, File rom, File output); @Override void apply(boolean ignoreChecksum); static boolean checkMagic(File f); static UpsCrc readUpsCrc(Context context, File f);  }
@Test public void testApply() throws Exception { assertTrue(ApplyPatch("/ups/readUpsCrc.ups", "/ups/readUpsCrc.bin", "/ups/readUpsCrc_m.bin")); }