/
echi_files.rb
208 lines (188 loc) · 6.44 KB
/
echi_files.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# This library is used to process Avaya CMS ECHI Files
#
# Author:: Jason Goecke (mailto:jason@goecke.net)
# Copyright:: Copyright (c) 2009 Jason Goecke
# License:: Distributes under the MIT License
#
# This class contains the methods for processing both
# binary and ascii files from the Avaya CMS
require 'yaml'
require 'fastercsv'
class EchiFiles
#Load the associated schema definitions of the Avaya ECHI files
def initialize
@extended = YAML::load_file(File.expand_path(File.dirname(__FILE__) + "/extended-definition.yml"))
@standard = YAML::load_file(File.expand_path(File.dirname(__FILE__) + "/standard-definition.yml"))
end
#Method to determine if the file is binary or ASCII encoded
def detect_filetype(filehandle)
if filehandle.read(1).is_binary_data?
type = 'BINARY'
else
type = 'ASCII'
end
filehandle.rewind
return type
end
#Method for parsing the various datatypes from the binary ECHI file
def dump_binary(filehandle, type, length)
case type
when 'int'
#Process integers, assigning appropriate profile based on length
#such as long int, short int and tiny int.
case length
when 4
value = filehandle.read(length).unpack("l").first.to_i
when 2
value = filehandle.read(length).unpack("s").first.to_i
when 1
value = filehandle.read(length).unpack("U").first.to_i
end
#Process appropriate intergers into datetime format in the database
when 'datetime'
case length
when 4
value = filehandle.read(length).unpack("l").first.to_i
value = Time.at(value)
end
#Process strings
when 'str'
value = filehandle.read(length).unpack("M").first.to_s.rstrip
#Process individual bits that are booleans
when 'bool'
value = filehandle.read(length).unpack("b8").last.to_s
#Process that one wierd boolean that is actually an int, instead of a bit
when 'boolint'
value = filehandle.read(length).unpack("U").first.to_i
#Change the values of the field to Y/N for the varchar(1) representation of BOOLEAN
if value == 1
value = 'Y'
else
value = 'N'
end
end
return value
end
#Mehtod that performs the conversions of files
def convert_binary_file(filehandle, schema, extra_byte)
#Read header information first
fileversion = dump_binary(filehandle, 'int', 4)
filenumber = dump_binary(filehandle, 'int', 4)
bool_cnt = 0
bytearray = nil
data = Array.new
while filehandle.eof == FALSE do
record = Hash.new
schema["echi_records"].each do | field |
#We handle the 'boolean' fields differently, as they are all encoded as bits in a single 8-bit byte
if field["type"] == 'bool'
if bool_cnt == 0
bytearray = dump_binary(filehandle, field["type"], field["length"])
end
#Ensure we parse the bytearray and set the appropriate flags
#We need to make sure the entire array is not nil, in order to do Y/N
#if Nil we then set all no
if bytearray != '00000000'
if bytearray.slice(bool_cnt,1) == '1'
value = 'Y'
else
value = 'N'
end
else
value = 'N'
end
record.merge!({ field["name"] => value })
bool_cnt += 1
if bool_cnt == 8
bool_cnt = 0
end
else
#Process 'standard' fields
value = dump_binary(filehandle, field["type"], field["length"])
record.merge!({ field["name"] => value })
end
end
#Scan past the end of line record if enabled in the configuration file
#Comment this out if you do not need to read the 'extra byte'
if extra_byte
filehandle.read(1)
end
data << record
end
return data
end
#Method to create a Ruby hash out of the Avaya ECHI files
#@filehandle The filehandle
#@type Whether this is ASCII or Binary data
#@schema Whether this is the ECHI EXTENDED or STANDARD file format
def convert_ascii_file(filehandle, schema)
data = Array.new
filehandle.each do |line|
record = Hash.new
FasterCSV.parse(line) do |row|
cnt = 0
row.each do |field|
if field != nil
if schema["echi_records"][cnt]["type"] == "bool" || schema["echi_records"][cnt]["type"] == "boolint"
case field
when "0"
record.merge!({ schema["echi_records"][cnt]["name"] => "N" })
when "1"
record.merge!({ schema["echi_records"][cnt]["name"] => "Y" })
when nil
record.merge!({ schema["echi_records"][cnt]["name"] => "N" })
else
record.merge!({ schema["echi_records"][cnt]["name"] => "Y" })
end
else
record.merge!({ schema["echi_records"][cnt]["name"] => field })
end
cnt += 1
end
end
end
data << record
end
return data
end
#Pass a filehandle of the file to process that includes
#@filehandle The filehandle
#@type Whether this is ASCII or Binary data
#@format Whether this is the ECHI EXTENDED or STANDARD file format
#@extra_byte Set to true if you want to read an extra byte at the end of each record
#This method will return an array of hashes of the resulting data processed
def process_file(filehandle, format, extra_byte)
#Set the appropriate schema format for standard or extended from the Avaya CMS
case format
when 'EXTENDED'
schema = @extended
when 'STANDARD'
schema = @standard
end
#Process based on the filetype passed
case detect_filetype(filehandle)
when 'ASCII'
return convert_ascii_file(filehandle, schema)
when 'BINARY'
return convert_binary_file(filehandle, schema, extra_byte)
end
end
#Method used to strip special characters
#@data An Array of Hashes to be processed
#@fields An array of fields to strip characters from
#@characters An Array of characters to be stripped
def strip_special_characters(data, fields, characters)
stripped_data = Array.new
data.each do |row|
fields.each do |field|
if field == row[0]
characters.each do |character|
row[1].gsub!(character.chr, "")
end
end
end
stripped_data << row
end
return stripped_data
end
end