#!/usr/bin/env python # MIT License, Copyright 2015 t0x0 # Full text in 'LICENSE' file # May not work for any FFU files other than the Raspberry Pi 2 Windows 10 Insider Preview image. # Tested on the 2015-05-12 release image with Python 2.7.9 # Use at your own risk, and let me know if it fails for your situation. me@t0x0.com import sys, os.path, struct, string from collections import namedtuple if len(sys.argv) < 2: sys.exit("Error: no filenames provided. Usage: ffu2img.py input.ffu [output.img]\nWarning, will overwrite output file without prior permission.") ffupath = sys.argv[1] if len(sys.argv) == 3: imgpath = sys.argv[2] else: imgpath = string.rsplit(ffupath, '.', 1)[0] + '.img' print 'Input File: ' + ffupath print 'Output File: ' + imgpath SecurityHeader = namedtuple("SecurityHeader", "cbSize signature dwChunkSizeInKb dwAlgId dwCatalogSize dwHashTableSize") ImageHeader = namedtuple("ImageHeader", "cbSize signature ManifestLength dwChunkSize") StoreHeader = namedtuple("StoreHeader", "dwUpdateType MajorVersion MinorVersion FullFlashMajorVersion FullFlashMinorVersion szPlatformId dwBlockSizeInBytes dwWriteDescriptorCount dwWriteDescriptorLength dwValidateDescriptorCount dwValidateDescriptorLength dwInitialTableIndex dwInitialTableCount dwFlashOnlyTableIndex dwFlashOnlyTableCount dwFinalTableIndex dwFinalTableCount") BlockDataEntry = namedtuple("BlockDataEntry", "dwDiskAccessMethod dwBlockIndex dwLocationCount dwBlockCount") ffufp = open(ffupath, 'rb') imgfp = open(imgpath, 'wb') logfp = open('ffu2img.log', 'w') def readsecheader(): (cbSize, signature, dwChunkSizeInKb, dwAlgId, dwCatalogSize, dwHashTableSize) = struct.unpack(" 1: print('\r' + str(iBlock) + ' blocks, ' + str((iBlock*FFUStoreHeader.dwBlockSizeInBytes)/1024) + 'kb written - Delay expected. Please wait.'), oldblockcount = CurrentBlockDataEntry.dwBlockCount for key, val in CurrentBlockDataEntry._asdict().iteritems(): logfp.write(key + ' = ' + str(val) + '\n') curraddress = ffufp.tell() ffufp.seek(blockdataaddress+(iBlock*FFUStoreHeader.dwBlockSizeInBytes)) imgfp.seek(CurrentBlockDataEntry.dwBlockCount*FFUStoreHeader.dwBlockSizeInBytes) imgfp.write(ffufp.read(FFUStoreHeader.dwBlockSizeInBytes)) ffufp.seek(curraddress) iBlock = iBlock + 1 print '\nWrite complete.' imgfp.close() ffufp.close() logfp.close()