pack_ramdisk.lua (5642B)
1 #!/usr/bin/env luajit 2 -- pack_ramdisk.lua - Generates packed.bin from iso_includes directory 3 -- Usage: luajit pack_ramdisk.lua <source_dir> <output_file> 4 5 local source_dir = arg[1] or "iso_includes" 6 local output_file = arg[2] or "OS/packed.bin" 7 8 -- Helper function to check if a file is binary 9 local function isBinary(content) 10 for i = 1, #content do 11 local byte = content:byte(i) 12 if byte < 32 and byte ~= 9 and byte ~= 10 and byte ~= 13 then 13 return true 14 end 15 if byte > 127 then 16 return true 17 end 18 end 19 return false 20 end 21 22 -- Base64 encoding 23 local function base64Encode(data) 24 local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' 25 local result = {} 26 27 for i = 1, #data, 3 do 28 local b1 = data:byte(i) 29 local b2 = data:byte(i + 1) 30 local b3 = data:byte(i + 2) 31 32 local c1 = b:sub(bit.rshift(b1, 2) + 1, bit.rshift(b1, 2) + 1) 33 34 if b2 then 35 local c2 = b:sub(bit.bor(bit.lshift(bit.band(b1, 0x03), 4), bit.rshift(b2, 4)) + 1, bit.bor(bit.lshift(bit.band(b1, 0x03), 4), bit.rshift(b2, 4)) + 1) 36 37 if b3 then 38 local c3 = b:sub(bit.bor(bit.lshift(bit.band(b2, 0x0F), 2), bit.rshift(b3, 6)) + 1, bit.bor(bit.lshift(bit.band(b2, 0x0F), 2), bit.rshift(b3, 6)) + 1) 39 local c4 = b:sub(bit.band(b3, 0x3F) + 1, bit.band(b3, 0x3F) + 1) 40 table.insert(result, c1 .. c2 .. c3 .. c4) 41 else 42 local c3 = b:sub(bit.lshift(bit.band(b2, 0x0F), 2) + 1, bit.lshift(bit.band(b2, 0x0F), 2) + 1) 43 table.insert(result, c1 .. c2 .. c3 .. '=') 44 end 45 else 46 local c2 = b:sub(bit.lshift(bit.band(b1, 0x03), 4) + 1, bit.lshift(bit.band(b1, 0x03), 4) + 1) 47 table.insert(result, c1 .. c2 .. '==') 48 end 49 end 50 51 return table.concat(result) 52 end 53 54 -- Escape text content 55 local function escapeText(text) 56 local result = {} 57 for i = 1, #text do 58 local c = text:sub(i, i) 59 if c == "\\" then 60 table.insert(result, "\\\\") 61 elseif c == "\n" then 62 table.insert(result, "\\n") 63 elseif c == "\t" then 64 table.insert(result, "\\t") 65 elseif c == "\r" then 66 table.insert(result, "\\r") 67 else 68 table.insert(result, c) 69 end 70 end 71 return table.concat(result) 72 end 73 74 -- Recursively scan directory 75 local function scanDirectory(path, relative_path) 76 local dirs = {} 77 local files = {} 78 79 -- Get directory listing 80 local handle = io.popen("find " .. path .. " -mindepth 1 -maxdepth 1 2>/dev/null") 81 if not handle then 82 io.stderr:write("Error: Cannot read directory " .. path .. "\n") 83 return dirs, files 84 end 85 86 for entry in handle:lines() do 87 local name = entry:match("^.+/(.+)$") 88 local entry_relative = relative_path == "" and name or relative_path .. "/" .. name 89 90 -- Check if it's a directory 91 local is_dir = os.execute("test -d " .. entry .. " 2>/dev/null") == 0 92 93 if is_dir then 94 -- Add directory 95 table.insert(dirs, entry_relative) 96 -- Recursively scan subdirectory 97 local subdirs, subfiles = scanDirectory(entry, entry_relative) 98 for _, d in ipairs(subdirs) do 99 table.insert(dirs, d) 100 end 101 for _, f in ipairs(subfiles) do 102 table.insert(files, f) 103 end 104 else 105 -- Skip init.lua and packed.bin at any level 106 if entry_relative ~= "os/packed.bin" and entry_relative ~= "packed.bin" then 107 -- Add file 108 local file_handle = io.open(entry, "rb") 109 if file_handle then 110 local content = file_handle:read("*a") 111 file_handle:close() 112 113 table.insert(files, { 114 path = entry_relative, 115 content = content 116 }) 117 end 118 end 119 end 120 end 121 122 handle:close() 123 return dirs, files 124 end 125 126 -- Main 127 print("Packing ramdisk from: " .. source_dir) 128 print("Output file: " .. output_file) 129 130 local dirs, files = scanDirectory(source_dir, "") 131 132 -- Sort directories and files 133 table.sort(dirs) 134 table.sort(files, function(a, b) return a.path < b.path end) 135 136 print("Found " .. #dirs .. " directories and " .. #files .. " files") 137 138 -- Build packed format 139 local entries = {} 140 141 -- Add directories 142 for _, dir in ipairs(dirs) do 143 table.insert(entries, dir .. "/") 144 print(" DIR: " .. dir .. "/") 145 end 146 147 -- Add files 148 for _, file in ipairs(files) do 149 local entry 150 if isBinary(file.content) then 151 entry = file.path .. "~~~~BIN:" .. base64Encode(file.content) 152 print(" FILE: " .. file.path .. " (binary, " .. #file.content .. " bytes)") 153 else 154 local escaped = escapeText(file.content) 155 entry = file.path .. "~~~~" .. escaped 156 print(" FILE: " .. file.path .. " (text, original=" .. #file.content .. " escaped=" .. #escaped .. " entry=" .. #entry .. " bytes)") 157 end 158 table.insert(entries, entry) 159 end 160 161 -- Write output 162 -- Use null bytes as delimiter (won't appear in text files) 163 local ENTRY_SEP = "\x00\x00\x00\x00" 164 local packed = table.concat(entries, ENTRY_SEP) 165 print("\nDEBUG: Packed size: " .. #packed .. " bytes") 166 167 local out = io.open(output_file, "wb") 168 if not out then 169 io.stderr:write("Error: Cannot write to " .. output_file .. "\n") 170 os.exit(1) 171 end 172 173 out:write(packed) 174 out:close() 175 176 print("\nPacked ramdisk created: " .. output_file .. " (" .. #packed .. " bytes)")