View difference between Paste ID: SUx3zHVa and YXx5jjMV
SHOW: | | - or go back to the newest paste.
1
--[[
2
 PROGDOR file bundling program
3
4
Download with:
5
 pastebin get YXx5jjMV progdor
6
 std ld progdor progdor
7
8-
This is a stable release. You fool!
8+
This is a beta release. You fool!
9
To add:
10
	+pastebin upload
11
	+pastebin download
12
--]]
13
14
local doCompress = false --even if this is false, it will decompress compressed files. nifty, huh?
15
16
local doPastebin = false
17
local tArg = {...}
18
local input, outpath
19
if tArg[1] == "-p" then --the p is for pastebin
20
	doPastebin = true
21
	input = tArg[2]
22
	outpath = tArg[3]
23
else
24
	input = tArg[1]
25
	outpath = tArg[2]
26
end
27
28
local progdor = fs.getName(shell.getRunningProgram())
29
local dir = shell.dir()
30
local displayHelp = function()
31
	local txt = progdor.." <input> [output]\nCompression is "..tostring(doCompress):upper().."."
32
	return print(txt)
33
end
34
35
local yield = function()
36
	os.queueEvent("yield")
37
	os.pullEvent("yield")
38
end
39
40
-- CCA API START --
41
42
local bit = bit32
43
local function pack(bn1, bn2)
44
	return bit.band(bn1, 0xFF), bit.rshift(bn1, 8) + bit.lshift(bit.band(bn2, 0xF), 4), bit.rshift(bn2, 4)
45
end
46
local function upack(b1, b2, b3)
47
	return (b1 + bit.lshift(bit.band(b2, 0xF), 8)), (bit.lshift(b3,4) + bit.band(bit.rshift(b2, 4), 0xF))
48
end
49
local function createDict(bool)
50
	local ret = {}
51
	for i = 1, 255 do
52
		if bool then
53
			ret[string.char(i)] = i
54
		else
55
			ret[i] = string.char(i)
56
		end
57
	end
58
	if not bool then ret[256] = 256 end
59
	return ret
60
end
61
local function cp(sInput)
62
	local dic = createDict(true)
63
	local s = ""
64
	local ch
65
	local dlen = 256
66
	local result = {}
67
	local temp
68
	for i = 1, #sInput do
69
		if dlen == 4095 then
70
			result[#result + 1] = dic[s]
71
			result[#result + 1] = 256
72
			dic = createDict(true)
73
			dlen = 256
74
			s = ""
75
		end
76
		ch = sInput:sub(i, i)
77
		temp = s..ch
78
		if dic[temp] then
79
			s = temp
80
		else
81
			result[#result + 1] = dic[s]
82
			dlen = dlen	+1
83
			dic[temp] = dlen		
84
			s = ch
85
		end
86
	end
87
	result[#result + 1] = dic[s]
88
	
89
	return result
90
end
91
local function dc(data)
92
	local dic = createDict(false)	
93
	local entry
94
	local ch
95
	local currCode
96
	local result = {}
97
	result[#result + 1] = dic[data[1]]
98
	prefix = dic[data[1]]
99
	for i = 2, #data do
100
		currCode = data[i]
101
		if currCode == 256 then
102
			dic = createDict(false)
103
			prefix = ""
104
		else
105
			entry = dic[currCode]
106
			if entry then--exists in dictionary
107
				ch = entry:sub(1, 1)		
108
				result[#result + 1] = entry
109
				if prefix ~= "" then
110
					dic[#dic+1] = prefix .. ch
111
				end
112
			else	
113
				ch = prefix:sub(1, 1)
114
				result[#result + 1] = prefix..ch
115
				dic[#dic + 1] = prefix..ch
116
			end
117
		
118
			prefix = dic[currCode]
119
		end
120
	end
121
	
122
	return table.concat(result)
123
end
124
local function trim(inp)
125
	for i = 0,2 do
126
		if inp[#inp] == 0 then
127
			inp[#inp] = nil
128
		end
129
	end
130
end
131
local function decompress(input)
132
	local rec = {}
133
	for i = 1, #input, 3 do
134
		if i % 66 == 0 then
135
			yield()
136
		end
137
		rec[#rec+1], rec[#rec+2] = upack(input[i], input[i+1] or 0, input[i+2] or 0)
138
	end
139
	trim(rec)
140
	return dc(rec)
141
end
142
local function compress(input)
143
	local rec = {}
144
	local data = cp(input)
145
	for i=1, #data, 2 do
146
		yield()
147
		rec[#rec+1], rec[#rec+2], rec[#rec+3] = pack(data[i], data[i+1] or 0)
148
	end
149
	trim(rec)
150
	return rec
151
end
152
153
-- CCA API END --
154
155
local fixstr = function(str)
156
	return str:gsub("\\(%d%d%d)",string.char)
157
end
158
159
local explode = function(div,str)
160
    if (div=='') then return false end
161
    local pos,arr = 0,{}
162
    for st,sp in function() return string.find(str,div,pos,true) end do
163
        table.insert(arr,str:sub(pos,st-1))
164
        pos = sp + 1
165
    end
166
    table.insert(arr,str:sub(pos))
167
    return arr
168
end
169
local sanitize = function(sani,tize)
170
	local _,x = string.find(sani,tize)
171
	if x then
172
		return sani:sub(x+1)
173
	else
174
		return sani
175
	end
176
end
177
local tablize = function(input)
178
	if type(input) == "string" then
179
		return explode("\n",input)
180
	elseif type(input) == "table" then
181
		return table.concat(input,"\n")
182
	end
183
end
184
local compyress = function(input)
185
	return string.char(unpack(compress(input)))
186
end
187
local decompyress = function(input)
188
	local out = {}
189
	for a = 1, #input do
190
		table.insert(out,string.byte(input:sub(a,a)))
191
	end
192
	return decompress(out)
193
end
194
local listAll
195
listAll = function(_path, _files, noredundant)
196
	local path = _path or ""
197
	local files = _files or {}
198
	if #path > 1 then table.insert(files, path) end
199
	for _, file in ipairs(fs.list(path)) do
200
		local path = fs.combine(path, file)
201
		if (file ~= thisProgram) then
202
			local guud = true
203
			if guud then
204
				if fs.isDir(path) then
205
					listAll(path, files, noredundant)
206
				else
207
					table.insert(files, path)
208
				end
209
			end
210
		end
211
	end
212
	if noredundant then
213
		for a = 1, #files do
214
			if fs.isDir(tostring(files[a])) then
215
				if #fs.list(tostring(files[a])) ~= 0 then
216
					table.remove(files,a)
217
				end
218
			end
219
		end
220
	end
221
	return files
222
end
223
if not (input) then
224
	return displayHelp()
225
end
226
if not outpath then
227
	outpath = input
228
end
229
230
local choice = function(input,verbose)
231
	if not input then
232
		input = "yn"
233
	end
234
	if verbose then
235
		write("[")
236
		for a = 1, #input do
237
			write(input:sub(a,a):upper())
238
			if a < #input then
239
				write(",")
240
			end
241
		end
242
		write("]?")
243
	end
244
	local evt,char
245
	repeat
246
		evt,char = os.pullEvent("char")
247
	until string.find(input:lower(),char:lower())
248
	if verbose then
249
		print(char:upper())
250
	end
251
	local pos = string.find(input:lower(),char:lower())
252
	return pos, char:lower()
253
end
254
255
local postToPastebin = function(name, contents)
256
	local key = "0ec2eb25b6166c0c27a394ae118ad829"
257
	local response = http.post(
258
		"http://pastebin.com/api/api_post.php",
259
		"api_option=paste&"..
260
		"api_dev_key="..key.."&"..
261
		"api_paste_format=lua&"..
262
		"api_paste_name="..textutils.urlEncode(name).."&"..
263
		"api_paste_code="..textutils.urlEncode(contents)
264
	)
265
	if response then
266
		local sResponse = response.readAll()
267
		response.close()
268
		local sCode = string.match( sResponse, "[^/]+$" )
269
		return sCode
270
	else
271
		return false
272
	end
273
	return 
274
end
275
276
function doPack(input,output,doCompress,verbose) --make sure that shell exists before using verbose mode
277
	local tx = term.getTextColor()
278
	if not doPastebin then
279
		if not fs.exists(input) then return 3 end
280
		if fs.isReadOnly(output) then return 5 end
281
	end
282
	local packageSelf = true
283
	local packageReadOnly = true
284
	local ro_asked = false
285
	local ps_asked = false
286
	if fs.isDir(input) then --if not a package
287
		local out = {}
288
		local list = listAll(input,nil,true)
289
		if verbose then
290
			for a = 1, #list do --this checks for self and read-only files
291
				if fs.isReadOnly(list[a]) and (not ro_asked) then
292
					write("Include read-only files? ")
293
					if choice("yn",true) == 2 then
294
						packageReadOnly = false
295
					end
296
					ro_asked = true
297
				end
298
				if fs.combine("",list[a]) == shell.getRunningProgram() and (not ps_asked) then
299
					write("Include self? ")
300
					if choice("yn",true) == 2 then
301
						packageSelf = false
302
					end
303
					ps_asked = true
304
				end
305
			end
306
		end
307
		for a = 1, #list do --this loop kills fascists
308
			local is_self = fs.combine("",list[a]) == fs.combine("",shell.getRunningProgram())
309
			if not ((is_self and not packageSelf) or (fs.isReadOnly(list[a]) and not packageReadOnly)) then
310
				if verbose then
311
					write("[")
312
					if term.isColor() then term.setTextColor(colors.lightGray) end
313
					write(sanitize(list[a],fs.combine(dir,input)))
314
					term.setTextColor(tx)
315
					write("]")
316
				end
317
				if fs.isDir(list[a]) then
318
					out[sanitize(list[a],fs.combine(dir,input))] = true
319
				else
320
					local file = fs.open(list[a],"r")
321
					local cont = file.readAll()
322
					file.close()
323
					if doCompress then
324
						out[sanitize(list[a],fs.combine(dir,input))] = tablize(compyress(cont))
325
					else
326
						out[sanitize(list[a],fs.combine(dir,input))] = tablize(cont)
327
					end
328
				end
329
				local tx = term.getTextColor()
330
				if fs.getName(list[a]):lower() == "peasant" then
331
					if term.isColor() then
332
						term.setTextColor(colors.orange)
333
					end
334
					print(" BURNINATED")
335
				else
336
					if term.isColor() then
337
						term.setTextColor(colors.green)
338
					end
339
					print(" GOOD")
340
				end
341
				term.setTextColor(tx)
342
			else
343
				if fs.getName(list[a]):lower() == "peasant" then
344
					print("Spared "..list[a])
345
				else
346
					print("Skipped "..list[a])
347
				end
348
			end
349
		end
350
		local fullOutput = tostring(doCompress).."\n"..fixstr(textutils.serialize(out))
351
		local sCode
352
		if doPastebin then
353
			print("Uploading...")
354
			sCode = postToPastebin(input,fullOutput)
355
			return 7, "Code = '"..sCode.."'"
356
		else
357
			if fs.isDir(output) then fs.delete(output) end
358
			local file = fs.open(output,"w")
359
			file.write(fullOutput)
360
			file.close()
361
			return 1
362
		end
363
	else --if a package
364
		local list, isCompy
365
		if not doPastebin then
366
			local file = fs.open(input,"r")
367
			isCompy = file.readLine()
368
			list = file.readAll()
369
			file.close()
370
		else
371
			local file = http.get("http://pastebin.com/raw/"..tostring(input))
372
			if file then
373
				isCompy = file.readLine()
374
				list = file.readAll()
375
			else
376
				return 6
377
			end
378
		end
379
		local list = textutils.unserialize(list)
380
		if type(list) ~= "table" then
381
			return 4
382
		end
383
		if fs.exists(output) then
384
			fs.delete(output)
385
		end
386
		local amnt = 0
387
		for k,v in pairs(list) do
388
			amnt = amnt + 1
389
		end
390
		local num = 0
391
		for k,v in pairs(list) do
392
			num = num + 1
393
			if v == true then
394
				fs.makeDir(fs.combine(output,fs.combine(k,dir)))
395
			else
396
				local file = fs.open(fs.combine(output,fs.combine(k,dir)),"w")
397
				if verbose then
398
					write("[")
399
					if term.isColor() then term.setTextColor(colors.lightGray) end
400
					write(k)
401
					term.setTextColor(tx)
402
					write("]")
403
				end
404
				if isCompy:gsub(" ","") == "true" then
405
					file.write(decompyress(tablize(v)))
406
				else
407
					file.write(tablize(v))
408
				end
409
				file.close()
410
				local tx = term.getTextColor()
411
				if fs.getName(k):lower() == "peasant" then
412
					if term.isColor() then
413
						term.setTextColor(colors.orange)
414
					end
415
					print(" UNBURNINATED")
416
				else
417
					if term.isColor() then
418
						term.setTextColor(colors.green)
419
					end
420
					print(" GOOD")
421
				end
422
				term.setTextColor(tx)
423
			end
424
		end
425
		return 2
426
	end
427
end
428
429
local success, res, otherRes = pcall( function() return doPack(input,outpath,doCompress,true) end ) --functionized it!
430
431
if not success then
432
	term.setTextColor(colors.white)
433
	print("\n***Something went wrong!***")
434
	return printError(res)
435
end
436
437
if res then
438
	local msgs = {
439
		[1] = "Successfully packed '"..input.."/' as '"..outpath.."'",
440
		[2] = "Successfully unpacked '"..input.."' to '"..outpath.."/'",
441
		[3] = "That file/folder does not exist.",
442
		[4] = "That file isn't a packed folder.",
443
		[5] = "You don't have permission.",
444
		[6] = "Failed to connect.",
445
		[7] = "Uploaded successfully.",
446
	}
447
	print(msgs[res])
448
	if otherRes then
449
		print(otherRes)
450
	end
451
end