root/HTTP/Data.lua

Revision 1368 (checked in by rsz, 1 year ago)

cleanup

Line 
1 --------------------------------------------------------------------------------
2 -- Title:               Data.lua
3 -- Description:         Like a square peg in a round hole
4 -- Author:              Raphaël Szwarc http://alt.textdrive.com/lua/
5 -- Creation Date:       January 30, 2007
6 -- Legal:               Copyright (C) 2007 Raphaël Szwarc
7 --                      Under the terms of the MIT License
8 --                      http://www.opensource.org/licenses/mit-license.html
9 --------------------------------------------------------------------------------
10
11 -- import dependencies
12 local io = require( 'io' )
13 local string = require( 'string' )
14 local table = require( 'table' )
15
16 local assert = assert
17 local getfenv = getfenv
18 local getmetatable = getmetatable
19 local loadstring = loadstring
20 local pairs = pairs
21 local setfenv = setfenv
22 local setmetatable = setmetatable
23 local tonumber = tonumber
24 local tostring = tostring
25 local type = type
26
27 --------------------------------------------------------------------------------
28 -- Data
29 --------------------------------------------------------------------------------
30
31 module( 'Data' )
32 _VERSION = '1.0'
33
34 local self = setmetatable( _M, {} )
35 local meta = getmetatable( self )
36
37 --------------------------------------------------------------------------------
38 -- Utilities
39 --------------------------------------------------------------------------------
40
41 local encoders = {}
42
43 local function HexDecode( aString )
44     local aCoder = function( aValue )
45         return string.char( tonumber( aValue, 16 ) )
46     end
47
48     return aString:gsub( '(%x%x)', aCoder )
49 end
50
51 local function HexEncode( aString )
52     local aCoder = function( aValue )
53         return ( '%02x' ):format( aValue:byte() )
54     end
55
56     return aString:gsub( '.', aCoder )
57 end
58
59 local function DecodeFunction( aFunction )
60     return assert( loadstring( HexDecode( aFunction ) ) )
61 end
62
63 local function Decode( anObject )
64     local aChunk = assert( loadstring( anObject ) )
65    
66     setfenv( aChunk, { _ = {}, f = DecodeFunction } )
67     aChunk()
68        
69     return getfenv( aChunk )._
70 end
71
72 local function Encode( anObject, someReferences, aName )
73     local anEncoder = encoders[ type( anObject ) ]
74    
75     if anEncoder then
76         return anEncoder( anObject, someReferences or {}, aName )
77     end
78    
79     return 'nil'
80 end
81
82 local function EncodeBoolean( aBoolean )
83     return tostring( aBoolean )
84 end
85
86 local function EncodeFunction( aFunction )
87     return 'f"' .. HexEncode( string.dump( aFunction ) ) .. '"'
88 end
89
90 local function EncodeNumber( aNumber )
91     return tostring( aNumber )
92 end
93
94 local function EncodeString( aString )
95     return ( '%q' ):format( aString )
96 end
97
98 local function EncodeTable( aTable, someReferences, aName )
99     if not someReferences[ aTable ] then
100         local aBuffer = {}
101    
102         if aName then
103             aBuffer[ #aBuffer + 1 ] = '{}'
104         end
105    
106         aName = aName or '_'
107         someReferences[ aTable ] = aName
108        
109         for aKey, aValue in pairs( aTable ) do
110             local aLocalName = ( '%s[%s]' ):format( aName, Encode( aKey, someReferences, aName ) )
111            
112             aKey = Encode( aKey, someReferences, aLocalName )
113             aValue = Encode( aValue, someReferences, aLocalName )
114            
115             aBuffer[ #aBuffer + 1 ] = ( '%s[%s]=%s' ):format( aName, aKey, aValue )
116         end
117        
118         return table.concat( aBuffer, '\n' )
119     end
120
121     return someReferences[ aTable ]
122 end
123
124 encoders[ 'boolean' ] = EncodeBoolean
125 encoders[ 'function' ] = EncodeFunction
126 encoders[ 'number' ] = EncodeNumber
127 encoders[ 'string' ] = EncodeString
128 encoders[ 'table' ] = EncodeTable
129
130 --------------------------------------------------------------------------------
131 -- Metamethods
132 --------------------------------------------------------------------------------
133
134 function meta:__call( anObject )
135     if type( anObject ) == 'table' then
136         return Encode( anObject )
137     end
138    
139     return Decode( tostring( anObject ) )
140 end
141
142 function meta:__index( aKey )
143     local aFile = assert( io.open( aKey, 'rb' ) )
144     local aContent = aFile:read( '*a' )
145    
146     aFile:close()
147
148     return self( aContent )
149 end
150
151 function meta:__newindex( aKey, aValue )
152     local aFile = assert( io.open( aKey, 'wb' ) )
153
154     aFile:write( self( aValue ) )
155     aFile:close()
156 end
157
158 function meta:__concat( aValue )
159     return tostring( self ) .. tostring( aValue )
160 end
161
162 function meta:__tostring()
163     return ( '%s/%s' ):format( self._NAME, self._VERSION )
164 end
165
Note: See TracBrowser for help on using the browser.