~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/chai2010/gettext-go/gettext/mo/file.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
2
 
// Use of this source code is governed by a BSD-style
3
 
// license that can be found in the LICENSE file.
4
 
 
5
 
package mo
6
 
 
7
 
import (
8
 
        "bytes"
9
 
        "encoding/binary"
10
 
        "fmt"
11
 
        "io/ioutil"
12
 
        "strings"
13
 
)
14
 
 
15
 
const (
16
 
        MoHeaderSize        = 28
17
 
        MoMagicLittleEndian = 0x950412de
18
 
        MoMagicBigEndian    = 0xde120495
19
 
 
20
 
        EotSeparator = "\x04" // msgctxt and msgid separator
21
 
        NulSeparator = "\x00" // msgid and msgstr separator
22
 
)
23
 
 
24
 
// File represents an MO File.
25
 
//
26
 
// See http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
27
 
type File struct {
28
 
        MagicNumber  uint32
29
 
        MajorVersion uint16
30
 
        MinorVersion uint16
31
 
        MsgIdCount   uint32
32
 
        MsgIdOffset  uint32
33
 
        MsgStrOffset uint32
34
 
        HashSize     uint32
35
 
        HashOffset   uint32
36
 
        MimeHeader   Header
37
 
        Messages     []Message
38
 
}
39
 
 
40
 
// Load loads a named mo file.
41
 
func Load(name string) (*File, error) {
42
 
        data, err := ioutil.ReadFile(name)
43
 
        if err != nil {
44
 
                return nil, err
45
 
        }
46
 
        return LoadData(data)
47
 
}
48
 
 
49
 
// LoadData loads mo file format data.
50
 
func LoadData(data []byte) (*File, error) {
51
 
        r := bytes.NewReader(data)
52
 
 
53
 
        var magicNumber uint32
54
 
        if err := binary.Read(r, binary.LittleEndian, &magicNumber); err != nil {
55
 
                return nil, fmt.Errorf("gettext: %v", err)
56
 
        }
57
 
        var bo binary.ByteOrder
58
 
        switch magicNumber {
59
 
        case MoMagicLittleEndian:
60
 
                bo = binary.LittleEndian
61
 
        case MoMagicBigEndian:
62
 
                bo = binary.BigEndian
63
 
        default:
64
 
                return nil, fmt.Errorf("gettext: %v", "invalid magic number")
65
 
        }
66
 
 
67
 
        var header struct {
68
 
                MajorVersion uint16
69
 
                MinorVersion uint16
70
 
                MsgIdCount   uint32
71
 
                MsgIdOffset  uint32
72
 
                MsgStrOffset uint32
73
 
                HashSize     uint32
74
 
                HashOffset   uint32
75
 
        }
76
 
        if err := binary.Read(r, bo, &header); err != nil {
77
 
                return nil, fmt.Errorf("gettext: %v", err)
78
 
        }
79
 
        if v := header.MajorVersion; v != 0 && v != 1 {
80
 
                return nil, fmt.Errorf("gettext: %v", "invalid version number")
81
 
        }
82
 
        if v := header.MinorVersion; v != 0 && v != 1 {
83
 
                return nil, fmt.Errorf("gettext: %v", "invalid version number")
84
 
        }
85
 
 
86
 
        msgIdStart := make([]uint32, header.MsgIdCount)
87
 
        msgIdLen := make([]uint32, header.MsgIdCount)
88
 
        if _, err := r.Seek(int64(header.MsgIdOffset), 0); err != nil {
89
 
                return nil, fmt.Errorf("gettext: %v", err)
90
 
        }
91
 
        for i := 0; i < int(header.MsgIdCount); i++ {
92
 
                if err := binary.Read(r, bo, &msgIdLen[i]); err != nil {
93
 
                        return nil, fmt.Errorf("gettext: %v", err)
94
 
                }
95
 
                if err := binary.Read(r, bo, &msgIdStart[i]); err != nil {
96
 
                        return nil, fmt.Errorf("gettext: %v", err)
97
 
                }
98
 
        }
99
 
 
100
 
        msgStrStart := make([]int32, header.MsgIdCount)
101
 
        msgStrLen := make([]int32, header.MsgIdCount)
102
 
        if _, err := r.Seek(int64(header.MsgStrOffset), 0); err != nil {
103
 
                return nil, fmt.Errorf("gettext: %v", err)
104
 
        }
105
 
        for i := 0; i < int(header.MsgIdCount); i++ {
106
 
                if err := binary.Read(r, bo, &msgStrLen[i]); err != nil {
107
 
                        return nil, fmt.Errorf("gettext: %v", err)
108
 
                }
109
 
                if err := binary.Read(r, bo, &msgStrStart[i]); err != nil {
110
 
                        return nil, fmt.Errorf("gettext: %v", err)
111
 
                }
112
 
        }
113
 
 
114
 
        file := &File{
115
 
                MagicNumber:  magicNumber,
116
 
                MajorVersion: header.MajorVersion,
117
 
                MinorVersion: header.MinorVersion,
118
 
                MsgIdCount:   header.MsgIdCount,
119
 
                MsgIdOffset:  header.MsgIdOffset,
120
 
                MsgStrOffset: header.MsgStrOffset,
121
 
                HashSize:     header.HashSize,
122
 
                HashOffset:   header.HashOffset,
123
 
        }
124
 
        for i := 0; i < int(header.MsgIdCount); i++ {
125
 
                if _, err := r.Seek(int64(msgIdStart[i]), 0); err != nil {
126
 
                        return nil, fmt.Errorf("gettext: %v", err)
127
 
                }
128
 
                msgIdData := make([]byte, msgIdLen[i])
129
 
                if _, err := r.Read(msgIdData); err != nil {
130
 
                        return nil, fmt.Errorf("gettext: %v", err)
131
 
                }
132
 
 
133
 
                if _, err := r.Seek(int64(msgStrStart[i]), 0); err != nil {
134
 
                        return nil, fmt.Errorf("gettext: %v", err)
135
 
                }
136
 
                msgStrData := make([]byte, msgStrLen[i])
137
 
                if _, err := r.Read(msgStrData); err != nil {
138
 
                        return nil, fmt.Errorf("gettext: %v", err)
139
 
                }
140
 
 
141
 
                if len(msgIdData) == 0 {
142
 
                        var msg = Message{
143
 
                                MsgId:  string(msgIdData),
144
 
                                MsgStr: string(msgStrData),
145
 
                        }
146
 
                        file.MimeHeader.fromMessage(&msg)
147
 
                } else {
148
 
                        var msg = Message{
149
 
                                MsgId:  string(msgIdData),
150
 
                                MsgStr: string(msgStrData),
151
 
                        }
152
 
                        // Is this a context message?
153
 
                        if idx := strings.Index(msg.MsgId, EotSeparator); idx != -1 {
154
 
                                msg.MsgContext, msg.MsgId = msg.MsgId[:idx], msg.MsgId[idx+1:]
155
 
                        }
156
 
                        // Is this a plural message?
157
 
                        if idx := strings.Index(msg.MsgId, NulSeparator); idx != -1 {
158
 
                                msg.MsgId, msg.MsgIdPlural = msg.MsgId[:idx], msg.MsgId[idx+1:]
159
 
                                msg.MsgStrPlural = strings.Split(msg.MsgStr, NulSeparator)
160
 
                                msg.MsgStr = ""
161
 
                        }
162
 
                        file.Messages = append(file.Messages, msg)
163
 
                }
164
 
        }
165
 
 
166
 
        return file, nil
167
 
}
168
 
 
169
 
// Save saves a mo file.
170
 
func (f *File) Save(name string) error {
171
 
        return ioutil.WriteFile(name, f.Data(), 0666)
172
 
}
173
 
 
174
 
// Save returns a mo file format data.
175
 
func (f *File) Data() []byte {
176
 
        return encodeFile(f)
177
 
}
178
 
 
179
 
// String returns the po format file string.
180
 
func (f *File) String() string {
181
 
        var buf bytes.Buffer
182
 
        fmt.Fprintf(&buf, "# version: %d.%d\n", f.MajorVersion, f.MinorVersion)
183
 
        fmt.Fprintf(&buf, "%s\n", f.MimeHeader.String())
184
 
        fmt.Fprintf(&buf, "\n")
185
 
 
186
 
        for k, v := range f.Messages {
187
 
                fmt.Fprintf(&buf, `msgid "%v"`+"\n", k)
188
 
                fmt.Fprintf(&buf, `msgstr "%s"`+"\n", v.MsgStr)
189
 
                fmt.Fprintf(&buf, "\n")
190
 
        }
191
 
 
192
 
        return buf.String()
193
 
}