saveLocalData pitfall

I mentioned this a long time ago, at least I think I did. I couldn’t find it in previous posts when I did a search. saveLocalData could be chewing up memory for you and you won’t know it. It works just like saveProjectData and saveGlobalData with exceptions. LocalData and ProjectData can only be seen in the projects they were created in and GlobalData can be seen by any project. ProjectData is deleted when the project is deleted, but LocalData isn’t. The only way to get rid of LocalData is to do clearLocalData in the project it was created in. If you saveLocalData and then delete the project it was created in, the LocalData is still there but you might not remember the project name at a later date. If you know the project name, you can create the project and do a clearLocalData to get rid of it, then delete the project. I use the code below to find projects that still have LocalData in them. Run the code and look thru the list. Some things won’t make sense, but others might. Look for a project name that you recognize and see the LocalData associated with it. If it’s a program you deleted, you can create a project with that name and do a clearLocalData, then delete the project again. I don’t have a good layout of a plist file, so it’s possible that this code might not work for every plist file. Load the 2 sections below and see what you find.

PS. It’s better to use ProjectData or GlobalData instead of LocalData to avoid this problem.

displayMode(STANDARD)

function setup() 
    textMode(CORNER)
    binTab={
        ["0"]="0000",["1"]="0001",["2"]="0010",["3"]="0011",
        ["4"]="0100",["5"]="0101",["6"]="0110",["7"]="0111",
        ["8"]="1000",["9"]="1001",["a"]="1010",["b"]="1011",
        ["c"]="1100",["d"]="1101",["e"]="1110",["f"]="1111",
        ["A"]="1010",["B"]="1011",["C"]="1100",["D"]="1101",
        ["E"]="1110",["F"]="1111" }
    
    tab,t,h,osTab={},{},{},{}
    cnt,dy,count=0,0,0
    filler=""
    --[[    plist codes
    type    binary       hex    meaning        
    null    0000 0000    x00
    bool    0000 1000    x08    false
    bool    0000 1001    x09    true
    fill    0000 1111    x0F    fill byte
    int     0001 nnnn    x1n    Integer, # of bytes is 2^n
    real    0010 nnnn    x2n    Floating Point Number, # of bytes is 2^n
    date    0011 0011    x33    Date, 8-byte float, # of seconds since 2001-01-01
    data    0100 nnnn    x4n    Binary data,    n is # of bytes if F, count follows
    string  0101 nnnn    x5n    ASCII string,   n is # of chars if F, count follows
    string  0110 nnnn    x6n    Unicode string, n is # of chars if F, count follows 
    uid     1000 nnnn    x8n    n+1 is # of bytes (only used by NSKeyedArchiver)
    array   1010 nnnn    xAn    objref* n is count, if F, count follows
    set     1100 nnnn    xCn    objref* n is count, if F, count follows
    dict    1101 nnnn    xDn    keyref* objref* n is count, if F, count follows
    --]]
    readBinary()
    oSize=t[#t-25]  -- offset table byte size
    dSize=t[#t-24]  -- dictionary byte size
    start=t[#t-1]*256+t[#t]   -- start of table
    nbr=t[#t-17]*256+t[#t-16]   -- # of table entries   
    if oSize==2 then    -- 2 byte size
        for z=0,nbr*2-1,2 do
            xx=t[start+z]*256+t[start+z+1]
            osTab[cnt]=xx
            cnt=cnt+1
        end
    else
        for z=0,nbr-1 do
            xx=t[start+z]
            osTab[cnt]=xx
            cnt=cnt+1
        end
    end
    process(8)  -- start of plist
    table.insert(tab,"  ")
    table.insert(tab,"===== end of plist file =====")
end

function draw()
    background(85, 78, 78, 255)
    fill(255)
    for a,b in pairs(tab) do
        if #b>100 then
            text(string.sub(b,1,80).."...("..#b..")",5,HEIGHT-a*20+dy)
        else
            text(b,5,HEIGHT-a*20+dy)
        end
    end
end

function touched(t)
    if t.state==MOVING then
        dy=dy+t.deltaY
        if dy<0 then
            dy=0
        end
    end
end

function fi(v)
    count=count+v    
    filler=""
    for z=1,count do
        filler=filler.." "
    end
end
    
function process(offset) 
    code=t[offset]
    --print(string.format("%0x",code))
    if code==0x08 then
        table.insert(tab,filler.."false")
    elseif code==0x09 then
        table.insert(tab,filler.."true")
    elseif code>=0x10 and code<=0x1f then
        x101f(offset)
    elseif code>=0x20 and code<=0x2f then
        x202f(offset)
    elseif code==0x33 then
        x33(offset)
    elseif code>=0x50 and code<=0x5e then
        x515e(offset)
    elseif code==0x5f then
        x5f(offset)
    elseif code>=0x60 and code<=0x6e then
        x616e(offset)
    elseif code==0x6f then
        x6f(offset)
    elseif code>=0x80 and code<=0x8f then
        x808f(offset)
    elseif code>=0xa1 and code<=0xae then
        xa1ae(offset)
    elseif code==0xaf then
        xaf(offset)
    elseif code>=0xd0 and code<=0xde then
        xd1de(offset)
    elseif code==0xdf then
        xdf(offset)
    else
        print(string.format("missing code %0x, position %0x",code,offset))
    end
end

function x101f(offset)
    local str=filler..""
    local v=2^(code-0x10)
    for a=1,v do
        str=str..t[a+offset].." "
    end
    table.insert(tab,str)
end

function x202f(offset)
    local str=filler..""
    local str1=""
    local v=2^(code-0x20)   
    for a=1,v do
        local v1=string.format("%02x",t[a+offset])
        str1=str1..v1
    end
    str=str..hexToFloat(str1)
    table.insert(tab,str)
end 

function x33(offset)
    local str=filler..""
    local str1=""
    for a=1,8 do
        v=string.format("%02x",t[a+offset])
        str1=str1..v
    end
    local aa=hexToFloat(str1)//1
    local xx=978289200
    str=str..os.date("!%c",aa+xx)
    table.insert(tab,str)
end 

function x515e(offset)
    local str=filler..""
    for a=1,code-80 do
        str=str..string.char(t[a+offset])
    end
    table.insert(tab,str)
end 

function x5f(offset)
    local x1=t[offset+1]
    local x2=t[offset+2]
    local x4,pl
    if x1==16 then
        x4=x2
        pl=2
    elseif x1==17 then
        x4=256+x2
        pl=3
    else
        exit()
    end
    local str=filler..""
    for a=1,x4 do
        str=str..string.char(t[a+offset+pl])
    end
    table.insert(tab,str)
end

function x616e(offset)
    local str=filler..""
    for a=1,code-96 do
        str=str..string.char(t[a+offset])
    end
    table.insert(tab,str)
end 

function x6f(offset)
    local x1=t[offset+1]
    local x2=t[offset+2]
    local x4,pl
    if x1==16 then
        x4=x2
        pl=2
    elseif x1==17 then
        x4=256+x2
        pl=3
    else
        print("x6f error")
        exit()
    end 
    local str=filler..""
    for a=1,x4 do
        str=str..string.char(t[a+offset+pl])
    end
    table.insert(tab,str)
end

function x808f(offset)
    local str=filler..""
    for a=1,code-0x80+1 do
        str=str..string.char(t[a+offset])
    end
    table.insert(tab,str)
end

function xa1ae(offset)
    local offs=offset
    local size=code-0xa0  
    local offs=offs+1 
    if dSize==2 then 
        for z=offs,offs+size*2-1 do
            local val1=t[z]*256+t[z+1]
            fi(5)
            process(osTab[val1])
            table.insert(tab,"  ")
            fi(-5)
        end  
    else
        for z=offs,offs+size-1 do
            local val1=t[z]
            fi(5)
            process(osTab[val1])
            table.insert(tab,"  ")
            fi(-5)
        end  
    end
end 

function xaf(offset)
    local offs=offset
    local x1=t[offs+1]
    local x2=t[offs+2]
    local x4,pl,val1
    if x1==16 then
        x4=x2
        pl=2
    elseif x1==17 then
        x4=256+x2
        pl=3
    else
        print("xaf error")
        exit()
    end 
    local size=x4
    local offs=offs+pl+1
    if dSize==2 then
        for z=offs,offs+size*2-1,2 do
            val1=t[z]*256+t[z+1]
            process(osTab[val1])
            table.insert(tab,"  ")
        end 
    else
        for z=offs,offs+size-1 do
            val1=t[z]
            process(osTab[val1])
            table.insert(tab,"  ")
        end 
    end
end

function xd1de(offset)
    local offs=offset
    local size=code-0xd0
    local val1
    local offs=offs+1
    if dSize==2 then
        for z=offs,offs+size*2-1,2 do
            val1=t[z]*256+t[z+1]
            process(osTab[val1])
            fi(5)
            val1=t[z+size*2]*256+t[z+size*2+1]
            process(osTab[val1])
            fi(-5)
        end 
    else
        for z=offs,offs+size-1 do
            val1=t[z]
            process(osTab[val1])
            fi(5)
            val1=t[z+size]
            process(osTab[val1])
            fi(-5)
        end 
    end
end

function xdf(offset)
    local offs=offset   -- start of record df
    local x1=t[offs+1]  -- ??
    local x2=t[offs+2]  -- number of entries
    local x4,pl
    local val1
    if x1==16 then
        x4=x2
        pl=2
    elseif x1==17 then
        x4=256+x2
        pl=3
    else
        print("xdf error")
        exit()
    end    
    local size=x4
    local offs=offs+pl+1
    if dSize==2 then
        for z=offs,offs+size*2-1,2 do
            if count==0 then
                table.insert(tab,"  ")
            end
            if oSize==2 then
                val1=(t[z]*256+t[z+1])
                process(osTab[val1])
            else
                val1=(t[z]*256+t[z+1])
                process(osTab[val1])
            end
            
            fi(5)
            if oSize==2 then
                val1=(t[z+size*2]*256+t[z+size*2+1])
                process(osTab[val1])
            else
                val1=(t[z+size]*256+t[z+size])
                process(osTab[val1])
            end
            fi(-5)
        end
    else
        for z=offs,offs+size-1 do
            if count==0 then
                table.insert(tab,"  ")
            end
            val1=t[z]
            process(osTab[val1])
            fi(5)
            val1=t[z+size]
            process(osTab[val1])
            fi(-5)
        end 
    end
end
function readBinary()
    local file=os.getenv("HOME").."/Library/Preferences/com.twolivesleft.Codify.plist"
    local bFile=io.open(file,"rb")
    local bData=""
    if bFile then
        bData=bFile:read("*all")
        bFile:close()
    end
    for i=0,bData:len()-1 do        
        t[i]=bData:byte(i+1)
        h[i]=string.format("%02x",t[i])
    end
    --print(table.concat(h," "))
end

function hexToFloat(str)    -- 64 bit
    if tonumber(str)==0 then
        return(0)
    end
    local str1=""
    local a,z
    local h=#str//8
    if h~=1 and h~=2 then
        return("size error")
    end
    local e1={9,12}
    local c1={127,1023}
    local m1={10,13}
    local m2={32,64}
    for z=1,#str do
        a=string.sub(str,z,z)
        str1=str1..binTab[a]
    end
    local exp=string.sub(str1,2,e1[h])
    local c=tonumber(exp,2)-c1[h]
    local p=math.pow(2,c)
    local man="1"..string.sub(str1,m1[h],m2[h])
    local x=0
    for z=1,string.len(man) do
        if string.sub(man,z,z)=="1" then
            x=x+p
        end
        p=p/2
    end
    if string.sub(str1,1,1)=="1" then
        x=-x
    end 
    return(x)
end