diff --git a/cdre/libfixedwidth.go b/cdre/libfixedwidth.go
new file mode 100644
index 000000000..e698d38f7
--- /dev/null
+++ b/cdre/libfixedwidth.go
@@ -0,0 +1,71 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2013 ITsysCOM
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package cdre
+
+import (
+ "fmt"
+ "strconv"
+)
+
+// Used as generic function logic for various fields
+
+// Attributes
+// source - the base source
+// maxLen - the maximum field lenght
+// stripAllowed - whether we allow stripping of chars in case of source bigger than the maximum allowed
+// lStrip - if true, strip from beginning of the string
+// lPadding - if true, add chars at the beginning of the string
+// paddingChar - the character wich will be used to fill the existing
+func filterField(source string, maxLen int, stripAllowed, lStrip, lPadding, padWithZero bool) (string, error) {
+ if len(source) == maxLen { // the source is exactly the maximum length
+ return source, nil
+ }
+ if len(source) > maxLen { //the source is bigger than allowed
+ if !stripAllowed {
+ return "", fmt.Errorf("source %s is bigger than the maximum allowed length %d", source, maxLen)
+ }
+ if !lStrip {
+ return source[:maxLen], nil
+ } else {
+ diffIndx := len(source) - maxLen
+ return source[diffIndx:], nil
+ }
+ } else { //the source is smaller as the maximum allowed
+ paddingString := "%"
+ if padWithZero {
+ paddingString += "0" // it will not work for rPadding but this is not needed
+ }
+ if !lPadding {
+ paddingString += "-"
+ }
+ paddingString += strconv.Itoa(maxLen) + "s"
+ return fmt.Sprintf(paddingString, source), nil
+ }
+}
+
+/*
+type XmlCdreConfig struct {
+ XMLName xml.Name `xml:"configuration"`
+ Name string `xml:"name,attr"`
+ Type string `xml:"type,attr"`
+ Header XMLFWCdrHeader `xml:"header"`
+ Content XMLFWCdrContent `xml:"content"`
+ Footer XMLFWCdrFooter `xml:"footer"`
+}
+*/
diff --git a/config/xmlconfig.go b/config/xmlconfig.go
new file mode 100644
index 000000000..752e5403e
--- /dev/null
+++ b/config/xmlconfig.go
@@ -0,0 +1,103 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2013 ITsysCOM
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package config
+
+import (
+ "encoding/xml"
+ "errors"
+ "github.com/cgrates/cgrates/utils"
+ "io"
+)
+
+// Decodes a reader enforcing specific format of the configuration file
+func ParseCgrXmlConfig(reader io.Reader) (*CgrXmlCfgDocument, error) {
+ xmlConfig := new(CgrXmlCfgDocument)
+ decoder := xml.NewDecoder(reader)
+ if err := decoder.Decode(xmlConfig); err != nil {
+ return nil, err
+ }
+ return xmlConfig, nil
+}
+
+// Define a format for configuration file, one doc contains more configuration instances, identified by section, type and id
+type CgrXmlCfgDocument struct {
+ XMLName xml.Name `xml:"document"`
+ Type string `xml:"type,attr"`
+ Configurations []*CgrXmlConfiguration `xml:"configuration"`
+}
+
+// Storage for raw configuration
+type CgrXmlConfiguration struct {
+ XMLName xml.Name `xml:"configuration"`
+ Section string `xml:"section,attr"`
+ Type string `xml:"type,attr"`
+ Id string `xml:"id,attr"`
+ RawConfig []byte `xml:",innerxml"`
+}
+
+// The CdrExporter Fixed Width configuration instance
+type CgrXmlCdreFwCfg struct {
+ Header *CgrXmlCfgCdrHeader `xml:"header"`
+ Content *CgrXmlCfgCdrContent `xml:"content"`
+ Trailer *CgrXmlCfgCdrTrailer `xml:"trailer"`
+}
+
+// CDR header
+type CgrXmlCfgCdrHeader struct {
+ XMLName xml.Name `xml:"header"`
+ Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
+}
+
+// CDR content
+type CgrXmlCfgCdrContent struct {
+ XMLName xml.Name `xml:"content"`
+ Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
+}
+
+// CDR trailer
+type CgrXmlCfgCdrTrailer struct {
+ XMLName xml.Name `xml:"trailer"`
+ Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
+}
+
+// CDR field
+type CgrXmlCfgCdrField struct {
+ XMLName xml.Name `xml:"field"`
+ Name string `xml:"name,attr"`
+ Type string `xml:"type,attr"`
+ Width string `xml:"width,attr"`
+}
+
+func (xmlCfg *CgrXmlCfgDocument) GetCdreFWCfg(instName string) (*CgrXmlCdreFwCfg, error) {
+ cdrefwCfg := new(CgrXmlCdreFwCfg)
+ for _, cfgInst := range xmlCfg.Configurations {
+ if cfgInst.Section != "cdre" || cfgInst.Type != utils.CDR_FIXED_WIDTH || cfgInst.Id != instName {
+ continue
+ }
+ rawConfig := append([]byte(""), cfgInst.RawConfig...)
+ rawConfig = append(rawConfig, []byte("")...)
+ if err := xml.Unmarshal(rawConfig, cdrefwCfg); err != nil { // Encapsulate the rawConfig in one element so we can Unmarshall
+ return nil, err
+ } else if cdrefwCfg == nil {
+ return nil, errors.New("Could not unmarshal CgrXmlCdreFwCfg")
+ }
+ return cdrefwCfg, nil
+ }
+ return nil, nil
+}
diff --git a/config/xmlconfig_test.go b/config/xmlconfig_test.go
new file mode 100644
index 000000000..4834e9330
--- /dev/null
+++ b/config/xmlconfig_test.go
@@ -0,0 +1,108 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2013 ITsysCOM
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package config
+
+import (
+ "strings"
+ "testing"
+)
+
+var cfgDoc *CgrXmlCfgDocument // Will be populated by first test
+
+func TestParseXmlConfig(t *testing.T) {
+ cfgXmlStr := `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`
+ var err error
+ reader := strings.NewReader(cfgXmlStr)
+ if cfgDoc, err = ParseCgrXmlConfig(reader); err != nil {
+ t.Error(err.Error())
+ } else if cfgDoc == nil {
+ t.Fatal("Could not parse xml configuration document")
+ }
+}
+
+func TestGetCdreFWCfg(t *testing.T) {
+ cdreFWCfg, err := cfgDoc.GetCdreFWCfg("CDRE-FW1")
+ if err != nil {
+ t.Error(err)
+ } else if cdreFWCfg == nil {
+ t.Error("Could not parse CdreFw instance")
+ }
+ if len(cdreFWCfg.Header.Fields) != 8 {
+ t.Error("Unexpected number of header fields parsed", len(cdreFWCfg.Header.Fields))
+ }
+ if len(cdreFWCfg.Content.Fields) != 20 {
+ t.Error("Unexpected number of content fields parsed", len(cdreFWCfg.Content.Fields))
+ }
+ if len(cdreFWCfg.Trailer.Fields) != 9 {
+ t.Error("Unexpected number of trailer fields parsed", len(cdreFWCfg.Trailer.Fields))
+ }
+}