Skip to content

Migrate edicon to Ruby Implementation #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,16 @@ task :build_stub do
sh "ridk exec make -C src"
cp "src/stub.exe", "share/ocran/stub.exe"
cp "src/stubw.exe", "share/ocran/stubw.exe"
cp "src/edicon.exe", "share/ocran/edicon.exe"
end

file "share/ocran/stub.exe" => :build_stub
file "share/ocran/stubw.exe" => :build_stub
file "share/ocran/edicon.exe" => :build_stub

task :test => :build_stub

task :clean do
rm_f Dir["{bin,samples}/*.exe"]
rm_f Dir["share/ocran/{stub,stubw,edicon}.exe"]
rm_f Dir["share/ocran/{stub,stubw}.exe"]
sh "ridk exec make -C src clean"
end

Expand Down
146 changes: 146 additions & 0 deletions lib/ocran/ed_icon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# frozen_string_literal: true
require "fiddle/import"
require "fiddle/types"

module Ocran
# Changes the Icon in a PE executable.
module EdIcon
extend Fiddle::Importer
dlload "kernel32.dll"

include Fiddle::Win32Types
typealias "LPVOID", "void*"
typealias "LPCWSTR", "char*"

module Successive
include Enumerable

def each
return to_enum(__method__) unless block_given?

entry = self
while true
yield(entry)
entry = self.class.new(tail)
end
end

def tail
to_ptr + self.class.size
end
end

# Icon file header
IconHeader = struct(
[
"WORD Reserved",
"WORD ResourceType",
"WORD ImageCount"
]
).include(Successive)

icon_info = [
"BYTE Width",
"BYTE Height",
"BYTE Colors",
"BYTE Reserved",
"WORD Planes",
"WORD BitsPerPixel",
"DWORD ImageSize"
]

# Icon File directory entry structure
IconDirectoryEntry = struct(icon_info + ["DWORD ImageOffset"]).include(Successive)

# Group Icon Resource directory entry structure
IconDirResEntry = struct(icon_info + ["WORD ResourceID"]).include(Successive)

class IconFile < IconHeader
def initialize(icon_filename)
@data = File.binread(icon_filename)
super(Fiddle::Pointer.to_ptr(@data))
end

def entries
IconDirectoryEntry.new(self.tail).take(self.ImageCount)
end
end

class GroupIcon < IconHeader
attr_reader :size

def initialize(image_count, resource_type)
@size = IconHeader.size + image_count * IconDirResEntry.size
super(Fiddle.malloc(@size), Fiddle::RUBY_FREE)
self.Reserved = 0
self.ResourceType = resource_type
self.ImageCount = image_count
end

def entries
IconDirResEntry.new(self.tail).take(self.ImageCount)
end
end

MAKEINTRESOURCE = -> (i) { Fiddle::Pointer.new(i) }
RT_ICON = MAKEINTRESOURCE.(3)
RT_GROUP_ICON = MAKEINTRESOURCE.(RT_ICON.to_i + 11)

MAKELANGID = -> (p, s) { s << 10 | p }
LANG_NEUTRAL = 0x00
SUBLANG_DEFAULT = 0x01
LANGID = MAKELANGID.(LANG_NEUTRAL, SUBLANG_DEFAULT)

extern "DWORD GetLastError()"
extern "HANDLE BeginUpdateResourceW(LPCWSTR, BOOL)"
extern "BOOL EndUpdateResourceW(HANDLE, BOOL)"
extern "BOOL UpdateResourceW(HANDLE, LPCWSTR, LPCWSTR, WORD, LPVOID, DWORD)"

class << self
def update_icon(executable_filename, icon_filename)
update_resource(executable_filename) do |handle|
icon_file = IconFile.new(icon_filename)
icon_entries = icon_file.entries

# Create the RT_ICON resources
icon_entries.each_with_index do |entry, i|
if UpdateResourceW(handle, RT_ICON, 101 + i, LANGID, icon_file.to_i + entry.ImageOffset, entry.ImageSize) == 0
raise "failed to UpdateResource(#{GetLastError()})"
end
end

# Create the RT_GROUP_ICON structure
group_icon = GroupIcon.new(icon_file.ImageCount, icon_file.ResourceType)
group_icon.entries.zip(icon_entries).each_with_index do |(res, icon), i|
res.Width = icon.Width
res.Height = icon.Height
res.Colors = icon.Colors
res.Reserved = icon.Reserved
res.Planes = icon.Planes
res.BitsPerPixel = icon.BitsPerPixel
res.ImageSize = icon.ImageSize
res.ResourceID = 101 + i
end

# Save the RT_GROUP_ICON resource
if UpdateResourceW(handle, RT_GROUP_ICON, 100, LANGID, group_icon, group_icon.size) == 0
raise "Failed to create group icon(#{GetLastError()})"
end
end
end

def update_resource(executable_filename)
handle = BeginUpdateResourceW(executable_filename.encode("UTF-16LE"), 0)
if handle == Fiddle::NULL
raise "Failed to BeginUpdateResourceW(#{GetLastError()})"
end

yield(handle)

if EndUpdateResourceW(handle, 0) == 0
raise "Failed to EndUpdateResourceW(#{GetLastError()})"
end
end
end
end
end
3 changes: 2 additions & 1 deletion lib/ocran/stub_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ def initialize(path, chdir_before: nil, debug_extract: nil, debug_mode: nil,
stub.close

if icon_path
system(EDICON_PATH, stub.path, icon_path.to_s, exception: true)
require_relative "ed_icon"
EdIcon.update_icon(stub.path, icon_path.to_s)
end

File.open(stub, "ab") do |of|
Expand Down
10 changes: 3 additions & 7 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ STUB_CFLAGS = -D_CONSOLE $(CFLAGS)
STUBW_CFLAGS = -mwindows $(CFLAGS)
# -D_MBCS

all: stub.exe stubw.exe edicon.exe
all: stub.exe stubw.exe

stubicon.o: stub.rc
windres -i $< -o $@
Expand All @@ -21,9 +21,6 @@ stub.exe: $(OBJS) stub.o $(CONSOLE_OBJS)
stubw.exe: $(OBJS) stubw.o $(WINDOW_OBJS)
$(CC) $(STUBW_CFLAGS) $(OBJS) stubw.o $(WINDOW_OBJS) -o $@

edicon.exe: edicon.o
$(CC) $(CFLAGS) edicon.o -o edicon

error_console.o: error.c error.h
$(CC) $(STUB_CFLAGS) -o $@ -c $<

Expand Down Expand Up @@ -61,10 +58,9 @@ script_info_window.o: script_info.c script_info.h
$(CC) $(STUBW_CFLAGS) -o $@ -c $<

clean:
rm -f $(OBJS) stub.exe stubw.exe edicon.exe edicon.o stubw.o stub.o \
rm -f $(OBJS) stub.exe stubw.exe stubw.o stub.o \
$(CONSOLE_OBJS) $(WINDOW_OBJS)

install: stub.exe stubw.exe edicon.exe
install: stub.exe stubw.exe
cp -f stub.exe $(BINDIR)/stub.exe
cp -f stubw.exe $(BINDIR)/stubw.exe
cp -f edicon.exe $(BINDIR)/edicon.exe
146 changes: 0 additions & 146 deletions src/edicon.c

This file was deleted.