class WimParser

Parser for the Windows Image Format (WIM).

Information found here:
  http://www.microsoft.com/en-us/download/details.aspx?id=13096
  http://technet.microsoft.com/en-us/library/cc749478%28WS.10%29.aspx?ITPID=win7dtp
  http://www.freepatentsonline.com/y2010/0211943.html
  http://nunobrito1981.blogspot.com/2010/12/inaccuracy-on-wim-documentation.html

TODO: Add support for processing winnt.h GUID structures for wim_guid.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931%28v=vs.85%29.aspx
http://stackoverflow.com/questions/679381/accessing-guid-members-in-c-sharp

Constants

FLAG_HEADER_COMPRESSION
FLAG_HEADER_COMPRESS_LZX
FLAG_HEADER_COMPRESS_RESERVED
FLAG_HEADER_COMPRESS_XPRESS
FLAG_HEADER_METADATA_ONLY
FLAG_HEADER_READONLY
FLAG_HEADER_RESERVED

Flags values for the header struct

FLAG_HEADER_RESOURCE_ONLY
FLAG_HEADER_RP_FIX
FLAG_HEADER_SPANNED
FLAG_HEADER_WRITE_IN_PROGRESS
HEADER_V1_STRUCT
IMAGE_TAG
SIZEOF_HEADER_V1_STRUCT
VERSION

Attributes

filename[R]

Public Class Methods

new(filename) click to toggle source
# File lib/wim_parser.rb, line 68
def initialize(filename)
  @filename = filename
end

Public Instance Methods

header() click to toggle source
# File lib/wim_parser.rb, line 72
def header
  data = File.open(filename, "rb") do |f|
    f.read(SIZEOF_HEADER_V1_STRUCT)
  end
  ret = HEADER_V1_STRUCT.decode(data)
  raise "#{filename} is not a WIM file" if ret["image_tag"] != IMAGE_TAG
  ret
end
xml_data() click to toggle source
# File lib/wim_parser.rb, line 81
def xml_data
  header_data = header

  xml = File.open(filename, "rb") do |f|
    f.seek(header_data["xml_data_offset"])
    f.read(header_data["xml_data_size"])
  end
  xml.force_encoding("UTF-16")

  xml = Nokogiri::XML(xml).xpath("/WIM")

  ret = {}
  ret["total_bytes"] = xml.xpath("./TOTALBYTES").text.to_i
  ret["images"] = xml.xpath("./IMAGE").collect do |i|
    # Deal with hex time parts by removing the 0x prefix, padding with 0s to
    #   8 characters, appending the low part to the high part, converting
    #   to an integer, and then converting that to a time object.
    high_part     = i.xpath("./CREATIONTIME/HIGHPART").text[2..-1].rjust(8, '0')
    low_part      = i.xpath("./CREATIONTIME/LOWPART").text[2..-1].rjust(8, '0')
    creation_time = nt_filetime_to_ruby_time("#{high_part}#{low_part}".to_i(16))

    high_part     = i.xpath("./LASTMODIFICATIONTIME/HIGHPART").text[2..-1].rjust(8, '0')
    low_part      = i.xpath("./LASTMODIFICATIONTIME/LOWPART").text[2..-1].rjust(8, '0')
    last_mod_time = nt_filetime_to_ruby_time("#{high_part}#{low_part}".to_i(16))

    {
      "index"                  => i["INDEX"].to_i,
      "name"                   => i.xpath("./NAME").text,
      "description"            => i.xpath("./DESCRIPTION").text,
      "dir_count"              => i.xpath("./DIRCOUNT").text.to_i,
      "file_count"             => i.xpath("./FILECOUNT").text.to_i,
      "total_bytes"            => i.xpath("./TOTALBYTES").text.to_i,
      "hard_link_bytes"        => i.xpath("./HARDLINKBYTES").text.to_i,
      "creation_time"          => creation_time,
      "last_modification_time" => last_mod_time,
    }
  end
  ret
end

Private Instance Methods

nt_filetime_to_ruby_time(nt_time) click to toggle source
# File lib/wim_parser.rb, line 123
def nt_filetime_to_ruby_time(nt_time)
  # Convert an NT FILETIME to a Ruby Time object.
  nt_time = nt_time / 10_000_000 - 11_644_495_200
  nt_time = 0 if nt_time < 0
  Time.at(nt_time).gmtime
rescue RangeError
  nt_time
end