Use Unicode strings instead of bytes

This commit is contained in:
Elliot Nunn 2018-10-08 09:06:35 +08:00
parent 73f01d3e81
commit e3d3623de9
4 changed files with 49 additions and 49 deletions

View File

@ -32,3 +32,8 @@ def chunkify(b, blksize):
ab = b[i:i+blksize]
if len(ab) < blksize: ab += bytes(blksize-len(ab))
yield ab
def pstring(orig):
macroman = orig.encode('mac_roman')
return bytes([len(macroman)]) + macroman

View File

@ -1,13 +1,6 @@
import collections
_CASE = list(range(256)) # cheating, fix this!
def _to_lower(orig):
return bytes(_CASE[x] for x in orig)
class AbstractFolder(collections.MutableMapping):
def __init__(self, from_dict=()):
self._prefdict = {} # lowercase to preferred
@ -16,33 +9,35 @@ class AbstractFolder(collections.MutableMapping):
def __setitem__(self, key, value):
try:
key = key.encode('mac_roman')
key = key.decode('mac_roman')
except AttributeError:
pass
if len(key) > 31:
raise ValueError('Max filename length = 31')
key.encode('mac_roman')
lower = _to_lower(key)
if not (1 <= len(key) <= 31):
raise ValueError('Filename range 1-31 chars')
lower = key.lower()
self._prefdict[lower] = key
self._maindict[lower] = value
def __getitem__(self, key):
try:
key = key.encode('mac_roman')
key = key.decode('mac_roman')
except AttributeError:
pass
lower = _to_lower(key)
lower = key.lower()
return self._maindict[lower]
def __delitem__(self, key):
try:
value = value.encode('mac_roman')
value = value.decode('mac_roman')
except AttributeError:
pass
lower = _to_lower(key)
lower = key.lower()
del self._maindict[lower]
del self._prefdict[lower]
@ -58,7 +53,6 @@ class AbstractFolder(collections.MutableMapping):
def iter_paths(self):
for name, child in self.items():
print(name, child)
yield ((name,), child)
try:
childs_children = child.iter_paths()

View File

@ -1,5 +1,4 @@
import struct
import collections
from . import btree, bitmanip, directory
@ -101,19 +100,9 @@ class Volume(directory.AbstractFolder):
self.bootblocks = bytes(1024) # optional; for booting HFS volumes
self.crdate = 0 # date and time of volume creation
self.lsmod = 0 # date and time of last modification
self._name = b'Untitled'
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if len(value) > 27:
raise ValueError('Max volume name length = 27')
self._name = value
self.name = 'Untitled'
def read(self, from_volume):
self._dirtree = {}
self.bootblocks = from_volume[:1024]
drSigWord, drCrDate, drLsMod, drAtrb, drNmFls, \
@ -127,7 +116,7 @@ class Volume(directory.AbstractFolder):
self.crdate = drCrDate
self.lsmod = drLsMod
self.name = drVN
self.name = drVN.decode('mac_roman')
block2offset = lambda block: 512*drAlBlSt + drAlBlkSiz*block
extent2bytes = lambda firstblk, blkcnt: from_volume[block2offset(firstblk):block2offset(firstblk+blkcnt)]
@ -140,7 +129,7 @@ class Volume(directory.AbstractFolder):
pass
cnids = {}
childrenof = collections.defaultdict(dict)
childlist = [] # list of (parent_cnid, child_name, child_object) tuples
for rec in btree.dump_btree(extrec2bytes(drCTExtRec)):
# create a directory tree from the catalog file
@ -156,9 +145,9 @@ class Volume(directory.AbstractFolder):
datatype = (None, 'dir', 'file', 'dthread', 'fthread')[val[0]]
datarec = val[2:]
print(datatype + '\t' + repr(key))
print('\t', datarec)
print()
# print(datatype + '\t' + repr(key))
# print('\t', datarec)
# print()
if datatype == 'dir':
dirFlags, dirVal, dirDirID, dirCrDat, dirMdDat, dirBkDat, dirUsrInfo, dirFndrInfo \
@ -166,7 +155,7 @@ class Volume(directory.AbstractFolder):
f = Folder()
cnids[dirDirID] = f
childrenof[ckrParID][ckrCName] = f
childlist.append((ckrParID, ckrCName, f))
f.crdat, f.mddat, f.bkdat = dirCrDat, dirMdDat, dirBkDat
@ -181,7 +170,7 @@ class Volume(directory.AbstractFolder):
f = File()
cnids[filFlNum] = f
childrenof[ckrParID][ckrCName] = f
childlist.append((ckrParID, ckrCName, f))
f.crdat, f.mddat, f.bkdat = filCrDat, filMdDat, filBkDat
f.type, f.creator, f.flags, f.x, f.y = struct.unpack_from('>4s4sHHH', filUsrWds)
@ -206,9 +195,10 @@ class Volume(directory.AbstractFolder):
# elif datatype == 4:
# print('fil thread:', rec)
for parent, children in childrenof.items():
if parent != 1: # not the mythical parent of root!
cnids[parent].update(children)
for parent_cnid, child_name, child_obj in childlist:
if parent_cnid != 1:
parent_obj = cnids[parent_cnid]
parent_obj[child_name] = child_obj
self.update(cnids[2])
@ -290,8 +280,9 @@ class Volume(directory.AbstractFolder):
if wrap.cnid == 1: continue
obj = wrap.of
pstrname = bitmanip.pstring(path[-1])
mainrec_key = struct.pack('>LB', path2wrap[path[:-1]].cnid, len(path[-1])) + path[-1]
mainrec_key = struct.pack('>L', path2wrap[path[:-1]].cnid) + pstrname
if isinstance(wrap.of, File):
drFilCnt += 1
@ -339,7 +330,7 @@ class Volume(directory.AbstractFolder):
thdrec_key = struct.pack('>Lx', wrap.cnid)
thdrec_val_type = 4 if isinstance(wrap.of, File) else 3
thdrec_val = struct.pack('>BxxxxxxxxxLB', thdrec_val_type, path2wrap[path[:-1]].cnid, len(path[-1])) + path[-1]
thdrec_val = struct.pack('>BxxxxxxxxxL', thdrec_val_type, path2wrap[path[:-1]].cnid) + pstrname
catalog.append((thdrec_key, thdrec_val))
@ -371,13 +362,16 @@ class Volume(directory.AbstractFolder):
drWrCnt = 0 # ????volume write count
drVCSize = drVBMCSize = drCtlCSize = 0
drAtrb = 1<<8 # volume attributes (hwlock, swlock, CLEANUNMOUNT, badblocks)
drVN = self.name
drVN = self.name.encode('mac_roman')
drVolBkUp = 0 # date and time of last backup
drVSeqNum = 0 # volume backup sequence number
drFndrInfo = bytes(32) # information used by the Finder
drCrDate = self.crdate
drLsMod = self.lsmod
if not (1 <= len(drVN) <= 27):
raise ValueError('Volume name range 1-27 chars')
vib = struct.pack('>2sLLHHHHHLLHLH28pLHLLLHLL32sHHHLHHxxxxxxxxLHHxxxxxxxx',
drSigWord, drCrDate, drLsMod, drAtrb, drNmFls,
drVBMSt, drAllocPtr, drNmAlBlks, drAlBlkSiz, drClpSiz, drAlBlSt,

View File

@ -2,10 +2,16 @@ from machfs import *
import os
import time
def test_upperlower():
h = Volume()
h['alpha'] = File()
assert h['alpha'] is h['ALPHA']
assert list(h.keys()) == ['alpha']
def test_roundtrip():
h = Volume()
f = File()
h[b'single file'] = f
h['single file'] = f
f.data = f.rsrc = b'1234' * 4096
copies = [h.write(800*1024)]
@ -16,21 +22,18 @@ def test_roundtrip():
assert copies[0] == copies[1]
assert copies[1] == copies[2]
assert f.data in copies[-1]
def test_macos_mount():
h = Volume()
h.name = b'ElmoTest'
h.name = 'ElmoTest'
hf = File()
hf.data = b'12345' * 10
for i in reversed(range(100)):
last = b'testfile-%03d' % i
last = 'testfile-%03d' % i
h[last] = hf
ser = h.write(10*1024*1024)
h2 = Volume()
h2.read(ser)
assert h2[b'testfile-000'].data == hf.data
open('/tmp/SMALL.dmg','wb').write(ser)
os.system('hdiutil attach /tmp/SMALL.dmg')
n = 10
@ -44,6 +47,10 @@ def test_macos_mount():
pass
else:
break
recovered = open('/Volumes/ElmoTest/' + last.decode('ascii'),'rb').read()
recovered = open('/Volumes/ElmoTest/' + last,'rb').read()
os.system('umount /Volumes/ElmoTest')
assert recovered == hf.data
# h2 = Volume()
# h2.read(ser)
# assert h2['testfile-000'].data == hf.data