Skip to content

Commit af1ca2b

Browse files
committed
Started Javascript JPKExt Library
* Python prototype (that doesn't work correctly) developed with Cesar Gimenes (from CubicBox) at Intel IoT Roadshow * Modifications to the JPAK2 Extended Mode Specification to be more powerfull * Started a Javascript Library to pack/unpack (since the Python failed)
1 parent 33e16f9 commit af1ca2b

10 files changed

Lines changed: 353 additions & 34 deletions

File tree

doc/JPAK2/Extended Mode/README.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ The JPAK Meta Storage is similar to JPAK Filetable Structure, but aditionally ha
3131
| ------------ | ------------- | ------------------------------------------------- |
3232
| 0x0 | 0x4 | JMS1 Magic Number |
3333
| 0x4 | 0xC | Padding (0x00) |
34-
| 0x**V** | 0x**U** | JSON Volume Table |
34+
| 0xC | 0x**U** | JSON Volume Table |
3535
| 0x**U** | 0x**W** | JSON File Table |
3636
| 0x**X** | 0x**X+4** | `uint32_t` Producer ID (Look JPAK2.0 spec at 2.1) |
3737
| 0x**X+4** | 0x**X+8** | `uint32_t` JPAK Flags (Look JPAK2.0 spec at 2.1) |
@@ -41,15 +41,11 @@ The JPAK Meta Storage is similar to JPAK Filetable Structure, but aditionally ha
4141
The JSON Filetable is the same, the offset is relative to the first volume. The JSON Volume Table is as follow:
4242

4343
{
44-
"0" : {
44+
"vol0.jds" : {
4545
"filename" : "vol0.jds", // Volume Filename
46-
"start" : "0", // Start of volume in Bytes
47-
"end" : "1024", // End of volume in Bytes
4846
},
49-
"1" : {
47+
"vol1.jds" : {
5048
"filename" : "vol1.jds", // Volume Filename
51-
"start" : "1024", // Start of volume in Bytes
52-
"end" : "4096", // End of volume in Bytes
5349
}
5450
}
5551

doc/JPAK2/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ And for the file entries:
3131
"size" : FILESIZE // The file size
3232
"aeskey" : AESKEY // File key if != false
3333
"zlib" : FALSE/TRUE // If file is compressed
34+
"volume" : VOLUMEID // ID from VolumeTable
3435
"md5" : MD5SUM // Uncompresssed/unencrypted file MD5SUM
3536
}
3637

@@ -47,11 +48,13 @@ Example of JPAK Filesystem Table:
4748
'path': '/whatisthis',
4849
'offset': 13,
4950
'name': 'whatisthis',
51+
'volume': 'vol0.jdt',
5052
'size': 55
5153
},
5254
'test.html': {
5355
'path': '/test.html',
5456
'offset': 81,
57+
'volume': 'vol1.jdt',
5558
'name': 'test.html',
5659
'size': 49
5760
},
@@ -66,6 +69,7 @@ Example of JPAK Filesystem Table:
6669
't': {
6770
'path': '/3/t',
6871
'offset': 9104,
72+
'volume': 'vol0.jdt',
6973
'name': 't',
7074
'size': 0
7175
}

tools/extpacker.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var fs = require("fs");

tools/extpacker.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,30 @@
1515

1616
import struct, os, json, sys
1717
from jpaktool import *
18+
from jpakmodels import *
1819

1920
if len(sys.argv) > 3:
20-
metadata = sys.argv[1]
21+
metadataF = sys.argv[1]
2122
volume = sys.argv[2]
2223
user_args = sys.argv[3:]
23-
if os.path.isfile(metadata):
24+
metadata = JMS()
25+
if os.path.isfile(metadataF):
2426
print "Metadata %s has been found. Appending volume %s to JPAK" %(metadata, volume)
27+
f = open(metadataF, "rb")
28+
data = f.read()
29+
f.close()
30+
metadata.fromBinary(data)
31+
32+
jdata = JDS(os.path.basename(volume), volume)
33+
metadata.addVolume(jdata)
34+
35+
for ua in user_args:
36+
metadata.fromDirectory(ua, jdata)
37+
38+
metadata.toFile(metadataF)
39+
2540
else:
2641
print '''
2742
Usage: python packer.py metadata.jms volumeX.jds folder ...
28-
Ex: python packer.py myproject.jms volume0.jds /home/lucas/
43+
Ex: python extpacker.py myproject.jms volume0.jds /home/lucas/
2944
This will generate myproject.jms (or append a new volume) with contents of folder /home/lucas'''

tools/jpakmodels.py

Lines changed: 130 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,26 @@
1313
1414
'''
1515

16-
import json, struct
16+
import json, struct, os
1717

1818
class JPKVolumeEntry:
1919
'''
2020
{
21-
"filename": "vol0.jds",
22-
"start": 0,
23-
"end": 1000
21+
"filename": "vol0.jds"
2422
}
2523
'''
2624
filename = ""
2725
start = 0
2826
end = 0
2927

30-
def __init__(self, filename="", start=0, end=0):
28+
def __init__(self, filename=""):
3129
self.filename = filename
32-
self.start = start
33-
self.end = end
3430

3531
def toObject(self):
36-
return {"filename":self.filename,"start":self.start,"end":self.end}
32+
return {"filename":self.filename}
3733

3834
def fromObject(self, obj):
3935
self.filename = obj["filename"] if "filename" in obj else ""
40-
self.start = obj["start"] if "start" in obj else 0
41-
self.end = obj["end"] if "end" in obj else 0
4236

4337
class JPKFileEntry:
4438
'''
@@ -49,6 +43,7 @@ class JPKFileEntry:
4943
"size" : FILESIZE // The file size
5044
"aeskey" : AESKEY // File key if != false
5145
"zlib" : FALSE/TRUE // If file is compressed
46+
"volume" : VOLUMEID // ID from VolumeTable
5247
"md5" : MD5SUM // Uncompresssed/unencrypted file MD5SUM
5348
}
5449
'''
@@ -58,19 +53,21 @@ class JPKFileEntry:
5853
size = 0
5954
aeskey = ""
6055
zlib = False
56+
volume = ""
6157
md5 = ""
6258

63-
def __init__(self, name="", path="", offset=0, size=0, aeskey="", zlib=False, md5=""):
59+
def __init__(self, name="", path="", offset=0, size=0, aeskey="", zlib=False, volume="", md5=""):
6460
self.name = name
6561
self.path = path
6662
self.offset = offset
6763
self.size = size
6864
self.aeskey = aeskey
6965
self.zlib = zlib
66+
self.volume = volume
7067
self.md5 = md5
7168

7269
def toObject(self):
73-
return {"name":self.name, "path":self.path, "offset":self.offset, "size":self.size, "aeskey":self.aeskey, "zlib":self.zlib, "md5": self.md5}
70+
return {"name":self.name, "path":self.path, "offset":self.offset, "size":self.size, "aeskey":self.aeskey, "zlib":self.zlib, "volume":self.volume, "md5": self.md5}
7471

7572
def fromObject(self, obj):
7673
self.name = obj["name"] if "name" in obj else ""
@@ -79,6 +76,7 @@ def fromObject(self, obj):
7976
self.size = obj["size"] if "size" in obj else ""
8077
self.aeskey = obj["aeskey"] if "aeskey" in obj else ""
8178
self.zlib = obj["zlib"] if "zlib" in obj else ""
79+
self.volume = obj["volume"] if "volume" in obj else ""
8280
self.md5 = obj["md5"] if "md5" in obj else ""
8381

8482
class JPKDirectoryEntry:
@@ -110,6 +108,7 @@ def __init__(self, name="", path="", numfiles=0, directories={}, files={}, aeske
110108
def toObject(self):
111109
dirs = {}
112110
fls = {}
111+
113112
for key, value in self.directories.iteritems():
114113
dirs[key] = value.toObject()
115114

@@ -139,24 +138,53 @@ def fromObject(self, obj):
139138
def toJson(self):
140139
return json.dumps(self.toObject())
141140

142-
def fromJson(self, json):
143-
obj = json.loads(json)
141+
def fromJson(self, json_):
142+
obj = json.loads(json_)
144143
self.fromObject(obj)
145144

146-
def JMS:
145+
def fromDirectory(self, folder, jds):
146+
if os.path.isdir(folder):
147+
print "Folder: %s" % folder
148+
dt = os.listdir(folder)
149+
for i in dt:
150+
print "File: %s" %i
151+
if os.path.isfile(folder+"/"+i):
152+
offset, size = jds.addFromFile(folder+"/"+i)
153+
newfile = JPKFileEntry(name=os.path.basename(i), path=folder+"/"+i, offset=offset, size=size, volume=jds.name)
154+
self.files = {}
155+
self.files[os.path.basename(i)] = newfile
156+
self.numfiles += 1
157+
print self.name
158+
else:
159+
newdir = JPKDirectoryEntry(directories={},files={})
160+
newdir.fromDirectory(folder+"/"+i, jds)
161+
self.directories[os.path.basename(i)] = newdir
162+
163+
else:
164+
print "File: %s" % folder
165+
offset, size = jds.addFromFile(folder)
166+
newfile = JPKFileEntry(name=os.path.basename(folder), path=folder, offset=offset, size=size)
167+
self.files[os.path.basename(folder)] = newfile
168+
self.numfiles += 1
169+
170+
class JMS:
147171
MAGIC = "JMS1"
148-
volumeTable = []
172+
volumeTable = {}
149173
fileTable = JPKDirectoryEntry()
150174
producerId = 0
151175
flags = 0
152176
userflags = 0
153177

154-
def __init__(self, volumeTable=[], fileTable={}, producerId=0, flags=0, userflags=0):
178+
def __init__(self, volumeTable={}, fileTable=JPKDirectoryEntry(), producerId=0, flags=0, userflags=0):
155179
self.volumeTable = volumeTable
156180
self.fileTable = fileTable
157181
self.producerId = producerId
158182
self.flags = flags
159183
self.userflags = userflags
184+
self.fileTable.name = "ROOT"
185+
186+
def fromDirectory(self, directory, jds):
187+
self.fileTable.fromDirectory(directory, jds)
160188

161189
def toObject(self):
162190
vt = []
@@ -179,7 +207,7 @@ def fromObject(self, obj):
179207
if "fileTable" in obj:
180208
self.fileTable.fromObject(obj["fileTable"])
181209

182-
self.volumeTable = []
210+
self.volumeTable = {}
183211

184212
if "volumeTable" in obj:
185213
for value in obj["volumeTable"]:
@@ -194,18 +222,96 @@ def fromBinary(self, data):
194222
self.MAGIC = "JMS1"
195223
return
196224

197-
fileTableOffset = struct.unpack("<I", data[len(data)-4:len(data)])
225+
fileTableOffset = struct.unpack("<I", data[len(data)-4:len(data)])[0]
198226
volumeTableSize = fileTableOffset - 0xC
199227
fileTableSize = len(data) - fileTableOffset - 12
200228

201-
fileTableData = json.loads(data[fileTableOffset:fileTableOffset+fileTableSize])
229+
fileTableData = json.loads(data[fileTableOffset:fileTableOffset+fileTableSize-4])
202230
volumeTableData = json.loads(data[0xC:volumeTableSize+0xC])
203231

204232
self.fileTable = JPKDirectoryEntry()
205-
self.fileTable.fromJson(fileTableData)
233+
self.fileTable.fromObject(fileTableData)
206234

207-
self.volumeTable = []
208-
for value in volumeTableData:
235+
self.volumeTable = {}
236+
for key, value in volumeTableData.iteritems():
209237
v = JPKVolumeEntry()
210238
v.fromObject(value)
211-
self.volumeTable.append(v)
239+
self.volumeTable[key] = v
240+
241+
def toBinary(self):
242+
data = self.MAGIC
243+
data += "\x00" * 8
244+
vt = {}
245+
246+
for key, value in self.volumeTable.iteritems():
247+
vt[key] = value.toObject()
248+
data += json.dumps(vt)
249+
250+
fileTableOffset = len(data)
251+
data += self.fileTable.toJson()
252+
data += struct.pack("<4I", self.producerId, self.flags, self.userflags, fileTableOffset)
253+
return data
254+
255+
def addVolume(self, jds):
256+
if jds.name in self.volumeTable:
257+
print "Volume already exists! %s" % jds.name
258+
return
259+
260+
print self.volumeTable
261+
volume = JPKVolumeEntry(jds.filename)
262+
self.volumeTable[jds.name] = volume
263+
264+
def toFile(self, filename):
265+
data = self.toBinary()
266+
f = open(filename, "wb")
267+
f.write(data)
268+
f.close()
269+
270+
class JDS:
271+
MAGIC = "JDS1"
272+
name = ""
273+
filename = ""
274+
fd = None
275+
CHUNK = 4096
276+
277+
def __init__(self, name, filename):
278+
self.filename = filename
279+
self.name = name
280+
if os.path.isfile(filename):
281+
self.fd = open(filename, "rb+")
282+
else:
283+
self.fd = open(filename, "wb+")
284+
285+
self.fd.seek(0,2)
286+
if self.fd.tell() == 0:
287+
self.__buildHeader()
288+
self.fd.seek(0)
289+
290+
def __buildHeader(self):
291+
print "Creating Header"
292+
self.fd.write(self.MAGIC)
293+
self.fd.write("\x00"*8)
294+
295+
def add(self, data):
296+
offset = fd.tell()
297+
size = len(data)
298+
self.fd.write(data)
299+
return offset, size
300+
301+
def addFromFile(self, filename):
302+
f = open(filename,"rb")
303+
offset = self.fd.tell()
304+
f.seek(0,2)
305+
size = f.tell()
306+
f.seek(0)
307+
c = 0
308+
while c < size:
309+
chunk = self.CHUNK if size - c > self.CHUNK else size - c
310+
data = f.read(chunk)
311+
self.fd.write(data)
312+
c += chunk
313+
return offset, size
314+
315+
def close(self):
316+
self.fd.close()
317+

0 commit comments

Comments
 (0)