~ubuntu-branches/ubuntu/trusty/libjaudiotagger-java/trusty

« back to all changes in this revision

Viewing changes to src/org/jaudiotagger/tag/datatype/PartOfSet.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2011-04-28 23:52:43 UTC
  • mfrom: (3.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20110428235243-pzalvw6lncis3ukf
Tags: 2.0.3-1
* d/control: Drop Depends on default-jre per Debian Java Policy as its
  a library package.
* d/watch: Fix to directly monitor SVN tags.
* Switch to 3.0 (quilt) format.
* Bump Standards-Version to 3.9.2 (no changes needed).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.jaudiotagger.tag.datatype;
2
 
 
3
 
import org.jaudiotagger.tag.InvalidDataTypeException;
4
 
import org.jaudiotagger.tag.TagOptionSingleton;
5
 
import org.jaudiotagger.tag.id3.AbstractTagFrameBody;
6
 
import org.jaudiotagger.tag.id3.valuepair.TextEncoding;
7
 
 
8
 
import java.nio.ByteBuffer;
9
 
import java.nio.CharBuffer;
10
 
import java.nio.charset.*;
11
 
import java.util.regex.Matcher;
12
 
import java.util.regex.Pattern;
13
 
 
14
 
/**
15
 
 * Represents the form 01/10 whereby the second part is optional. This is used by frame such as TRCK and TPOS
16
 
 *
17
 
 * Some applications like to prepend the count with a zero to aid sorting, (i.e 02 comes before 10)
18
 
 */
19
 
@SuppressWarnings({"EmptyCatchBlock"})
20
 
public class PartOfSet extends AbstractString
21
 
{
22
 
    /**
23
 
     * Creates a new empty  PartOfSet datatype.
24
 
     *
25
 
     * @param identifier identifies the frame type
26
 
     * @param frameBody
27
 
     */
28
 
    public PartOfSet(String identifier, AbstractTagFrameBody frameBody)
29
 
    {
30
 
        super(identifier, frameBody);
31
 
    }
32
 
 
33
 
    /**
34
 
     * Copy constructor
35
 
     *
36
 
     * @param object
37
 
     */
38
 
    public PartOfSet(PartOfSet object)
39
 
    {
40
 
        super(object);
41
 
    }
42
 
 
43
 
    public boolean equals(Object obj)
44
 
    {
45
 
        return obj instanceof PartOfSet && super.equals(obj);
46
 
    }
47
 
 
48
 
    /**
49
 
     * Read a 'n' bytes from buffer into a String where n is the framesize - offset
50
 
     * so thefore cannot use this if there are other objects after it because it has no
51
 
     * delimiter.
52
 
     * <p/>
53
 
     * Must take into account the text encoding defined in the Encoding Object
54
 
     * ID3 Text Frames often allow multiple strings seperated by the null char
55
 
     * appropriate for the encoding.
56
 
     *
57
 
     * @param arr    this is the buffer for the frame
58
 
     * @param offset this is where to start reading in the buffer for this field
59
 
     * @throws NullPointerException
60
 
     * @throws IndexOutOfBoundsException
61
 
     */
62
 
    public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException
63
 
    {
64
 
        logger.finest("Reading from array from offset:" + offset);
65
 
 
66
 
        //Get the Specified Decoder
67
 
        String charSetName = getTextEncodingCharSet();
68
 
        CharsetDecoder decoder = Charset.forName(charSetName).newDecoder();
69
 
 
70
 
        //Decode sliced inBuffer
71
 
        ByteBuffer inBuffer = ByteBuffer.wrap(arr, offset, arr.length - offset).slice();
72
 
        CharBuffer outBuffer = CharBuffer.allocate(arr.length - offset);
73
 
        decoder.reset();
74
 
        CoderResult coderResult = decoder.decode(inBuffer, outBuffer, true);
75
 
        if (coderResult.isError())
76
 
        {
77
 
            logger.warning("Decoding error:" + coderResult.toString());
78
 
        }
79
 
        decoder.flush(outBuffer);
80
 
        outBuffer.flip();
81
 
 
82
 
        //Store value
83
 
        String stringValue = outBuffer.toString();
84
 
        value = new PartOfSetValue(stringValue);
85
 
 
86
 
        //SetSize, important this is correct for finding the next datatype
87
 
        setSize(arr.length - offset);
88
 
        logger.info("Read SizeTerminatedString:" + value + " size:" + size);
89
 
    }
90
 
 
91
 
    /**
92
 
     * Write String into byte array
93
 
     * <p/>
94
 
     * It will remove a trailing null terminator if exists if the option
95
 
     * RemoveTrailingTerminatorOnWrite has been set.
96
 
     *
97
 
     * @return the data as a byte array in format to write to file
98
 
     */
99
 
    public byte[] writeByteArray()
100
 
    {
101
 
        String value = getValue().toString();
102
 
        byte[] data;
103
 
        //Try and write to buffer using the CharSet defined by getTextEncodingCharSet()
104
 
        try
105
 
        {
106
 
            if (TagOptionSingleton.getInstance().isRemoveTrailingTerminatorOnWrite())
107
 
            {
108
 
                if (value.length() > 0)
109
 
                {
110
 
                    if (value.charAt(value.length() - 1) == '\0')
111
 
                    {
112
 
                        value = value.substring(0, value.length() - 1);                        
113
 
                    }
114
 
                }
115
 
            }
116
 
 
117
 
            String charSetName = getTextEncodingCharSet();
118
 
            if (charSetName.equals(TextEncoding.CHARSET_UTF_16))
119
 
            {
120
 
                charSetName = TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT;
121
 
                CharsetEncoder encoder = Charset.forName(charSetName).newEncoder();
122
 
                //Note remember LE BOM is ff fe but this is handled by encoder Unicode char is fe ff
123
 
                ByteBuffer bb = encoder.encode(CharBuffer.wrap('\ufeff' +  value));
124
 
                data = new byte[bb.limit()];
125
 
                bb.get(data, 0, bb.limit());
126
 
 
127
 
            }
128
 
            else
129
 
            {
130
 
                 CharsetEncoder encoder = Charset.forName(charSetName).newEncoder();
131
 
                ByteBuffer bb = encoder.encode(CharBuffer.wrap( value));
132
 
                data = new byte[bb.limit()];
133
 
                bb.get(data, 0, bb.limit());
134
 
            }
135
 
        }
136
 
        //Should never happen so if does throw a RuntimeException
137
 
        catch (CharacterCodingException ce)
138
 
        {
139
 
            logger.severe(ce.getMessage());
140
 
            throw new RuntimeException(ce);
141
 
        }
142
 
        setSize(data.length);
143
 
        return data;
144
 
    }
145
 
 
146
 
    /**
147
 
     * Get the text encoding being used.
148
 
     * <p/>
149
 
     * The text encoding is defined by the frame body that the text field belongs to.
150
 
     *
151
 
     * @return the text encoding charset
152
 
     */
153
 
    protected String getTextEncodingCharSet()
154
 
    {
155
 
        byte textEncoding = this.getBody().getTextEncoding();
156
 
        String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding);
157
 
        logger.finest("text encoding:" + textEncoding + " charset:" + charSetName);
158
 
        return charSetName;
159
 
    }
160
 
 
161
 
    /**
162
 
     * Holds data
163
 
     *
164
 
      */
165
 
    public static class PartOfSetValue
166
 
    {
167
 
        private static final Pattern trackNoPatternWithTotalCount;
168
 
        private static final Pattern trackNoPattern;
169
 
 
170
 
        static
171
 
        {
172
 
            //Match track/total pattern allowing for extraneous nulls ectera at the end
173
 
            trackNoPatternWithTotalCount  = Pattern.compile("([0-9]+)/([0-9]+)(.*)", Pattern.CASE_INSENSITIVE);
174
 
            trackNoPattern                = Pattern.compile("([0-9]+)(.*)", Pattern.CASE_INSENSITIVE);
175
 
        }
176
 
 
177
 
        private static final String SEPARATOR = "/";
178
 
        private Integer count;
179
 
        private Integer total;
180
 
        private String  extra;   //Any extraneous info such as null chars
181
 
        public PartOfSetValue()
182
 
        {
183
 
 
184
 
        }
185
 
 
186
 
        /** When constructing from data
187
 
         *
188
 
         * @param value
189
 
         */
190
 
        public PartOfSetValue(String value)
191
 
        {
192
 
            
193
 
            Matcher m = trackNoPatternWithTotalCount.matcher(value);
194
 
            if (m.matches())
195
 
            {
196
 
                this.count = Integer.parseInt(m.group(1));
197
 
                this.total = Integer.parseInt(m.group(2));
198
 
                this.extra = m.group(3);
199
 
                return;
200
 
            }
201
 
 
202
 
            m = trackNoPattern.matcher(value);
203
 
            if (m.matches())
204
 
            {
205
 
                this.count = Integer.parseInt(m.group(1));
206
 
                this.extra = m.group(2);
207
 
            }
208
 
        }
209
 
 
210
 
        /**
211
 
         * Newly created
212
 
         *
213
 
         * @param count
214
 
         * @param total
215
 
         */
216
 
        public PartOfSetValue(Integer count,Integer total)
217
 
        {
218
 
            this.count = count;
219
 
            this.total = total;
220
 
        }
221
 
 
222
 
 
223
 
 
224
 
        public Integer getCount()
225
 
        {
226
 
            return count;
227
 
        }
228
 
 
229
 
        public Integer getTotal()
230
 
        {
231
 
            return total;
232
 
        }
233
 
 
234
 
        public void setCount(Integer count)
235
 
        {
236
 
            this.count=count;
237
 
        }
238
 
 
239
 
        public void setTotal(Integer total)
240
 
        {
241
 
            this.total=total;
242
 
 
243
 
        }
244
 
 
245
 
        public void setCount(String count)
246
 
        {
247
 
            try
248
 
            {
249
 
                this.count=Integer.parseInt(count);
250
 
            }
251
 
            catch(NumberFormatException nfe)
252
 
            {
253
 
 
254
 
            }
255
 
        }
256
 
 
257
 
        public void setTotal(String total)
258
 
        {
259
 
            try
260
 
            {
261
 
                this.total=Integer.parseInt(total);
262
 
            }
263
 
            catch(NumberFormatException nfe)
264
 
            {
265
 
 
266
 
            }
267
 
        }
268
 
 
269
 
        public String toString()
270
 
        {
271
 
            //Dont Pad
272
 
            StringBuffer sb = new StringBuffer();
273
 
            if(!TagOptionSingleton.getInstance().isPadNumbers())
274
 
            {
275
 
                if(count!=null)
276
 
                {
277
 
                    sb.append(count.intValue());
278
 
                }
279
 
                else if(total!=null)
280
 
                {
281
 
                    sb.append('0');
282
 
                }
283
 
                if(total!=null)
284
 
                {
285
 
                    sb.append(SEPARATOR).append(total);
286
 
                }
287
 
                if(extra!=null)
288
 
                {
289
 
                    sb.append(extra);
290
 
                }
291
 
            }
292
 
            else
293
 
            {
294
 
                if(count!=null)
295
 
                {
296
 
                    if(count>0 && count<10)
297
 
                    {
298
 
                        sb.append("0").append(count);
299
 
                    }
300
 
                    else
301
 
                    {
302
 
                        sb.append(count.intValue());
303
 
                    }
304
 
                }
305
 
                else if(total!=null)
306
 
                {
307
 
                    sb.append('0');
308
 
                }
309
 
                if(total!=null)
310
 
                {
311
 
                    if(total>0 && total<10)
312
 
                    {
313
 
                        sb.append(SEPARATOR + "0").append(total);
314
 
                    }
315
 
                    else
316
 
                    {
317
 
                        sb.append(SEPARATOR).append(total);
318
 
                    }
319
 
                }
320
 
                if(extra!=null)
321
 
                {
322
 
                    sb.append(extra);
323
 
                }
324
 
            }
325
 
            return sb.toString();
326
 
        }
327
 
 
328
 
    }
329
 
 
330
 
    public PartOfSetValue getValue()
331
 
    {
332
 
        return (PartOfSetValue)value;
333
 
    }
334
 
 
335
 
    public String toString()
336
 
    {
337
 
        return value.toString();
338
 
    }
 
1
package org.jaudiotagger.tag.datatype;
 
2
 
 
3
import org.jaudiotagger.tag.InvalidDataTypeException;
 
4
import org.jaudiotagger.tag.TagOptionSingleton;
 
5
import org.jaudiotagger.tag.id3.AbstractTagFrameBody;
 
6
import org.jaudiotagger.tag.id3.valuepair.TextEncoding;
 
7
import org.jaudiotagger.utils.EqualsUtil;
 
8
 
 
9
import java.nio.ByteBuffer;
 
10
import java.nio.CharBuffer;
 
11
import java.nio.charset.*;
 
12
import java.util.regex.Matcher;
 
13
import java.util.regex.Pattern;
 
14
 
 
15
/**
 
16
 * Represents the form 01/10 whereby the second part is optional. This is used by frame such as TRCK and TPOS
 
17
 *
 
18
 * Some applications like to prepend the count with a zero to aid sorting, (i.e 02 comes before 10)
 
19
 */
 
20
@SuppressWarnings({"EmptyCatchBlock"})
 
21
public class PartOfSet extends AbstractString
 
22
{
 
23
    /**
 
24
     * Creates a new empty  PartOfSet datatype.
 
25
     *
 
26
     * @param identifier identifies the frame type
 
27
     * @param frameBody
 
28
     */
 
29
    public PartOfSet(String identifier, AbstractTagFrameBody frameBody)
 
30
    {
 
31
        super(identifier, frameBody);
 
32
    }
 
33
 
 
34
    /**
 
35
     * Copy constructor
 
36
     *
 
37
     * @param object
 
38
     */
 
39
    public PartOfSet(PartOfSet object)
 
40
    {
 
41
        super(object);
 
42
    }
 
43
 
 
44
    public boolean equals(Object obj)
 
45
    {
 
46
        if(obj==this)
 
47
        {
 
48
            return true;
 
49
        }
 
50
 
 
51
        if (!(obj instanceof PartOfSet))
 
52
        {
 
53
            return false;
 
54
        }
 
55
 
 
56
        PartOfSet that = (PartOfSet) obj;
 
57
 
 
58
        return EqualsUtil.areEqual(value, that.value);
 
59
    }
 
60
 
 
61
    /**
 
62
     * Read a 'n' bytes from buffer into a String where n is the framesize - offset
 
63
     * so thefore cannot use this if there are other objects after it because it has no
 
64
     * delimiter.
 
65
     * <p/>
 
66
     * Must take into account the text encoding defined in the Encoding Object
 
67
     * ID3 Text Frames often allow multiple strings seperated by the null char
 
68
     * appropriate for the encoding.
 
69
     *
 
70
     * @param arr    this is the buffer for the frame
 
71
     * @param offset this is where to start reading in the buffer for this field
 
72
     * @throws NullPointerException
 
73
     * @throws IndexOutOfBoundsException
 
74
     */
 
75
    public void readByteArray(byte[] arr, int offset) throws InvalidDataTypeException
 
76
    {
 
77
        logger.finest("Reading from array from offset:" + offset);
 
78
 
 
79
        //Get the Specified Decoder
 
80
        String charSetName = getTextEncodingCharSet();
 
81
        CharsetDecoder decoder = Charset.forName(charSetName).newDecoder();
 
82
 
 
83
        //Decode sliced inBuffer
 
84
        ByteBuffer inBuffer = ByteBuffer.wrap(arr, offset, arr.length - offset).slice();
 
85
        CharBuffer outBuffer = CharBuffer.allocate(arr.length - offset);
 
86
        decoder.reset();
 
87
        CoderResult coderResult = decoder.decode(inBuffer, outBuffer, true);
 
88
        if (coderResult.isError())
 
89
        {
 
90
            logger.warning("Decoding error:" + coderResult.toString());
 
91
        }
 
92
        decoder.flush(outBuffer);
 
93
        outBuffer.flip();
 
94
 
 
95
        //Store value
 
96
        String stringValue = outBuffer.toString();
 
97
        value = new PartOfSetValue(stringValue);
 
98
 
 
99
        //SetSize, important this is correct for finding the next datatype
 
100
        setSize(arr.length - offset);
 
101
        logger.info("Read SizeTerminatedString:" + value + " size:" + size);
 
102
    }
 
103
 
 
104
    /**
 
105
     * Write String into byte array
 
106
     * <p/>
 
107
     * It will remove a trailing null terminator if exists if the option
 
108
     * RemoveTrailingTerminatorOnWrite has been set.
 
109
     *
 
110
     * @return the data as a byte array in format to write to file
 
111
     */
 
112
    public byte[] writeByteArray()
 
113
    {
 
114
        String value = getValue().toString();
 
115
        byte[] data;
 
116
        //Try and write to buffer using the CharSet defined by getTextEncodingCharSet()
 
117
        try
 
118
        {
 
119
            if (TagOptionSingleton.getInstance().isRemoveTrailingTerminatorOnWrite())
 
120
            {
 
121
                if (value.length() > 0)
 
122
                {
 
123
                    if (value.charAt(value.length() - 1) == '\0')
 
124
                    {
 
125
                        value = value.substring(0, value.length() - 1);                        
 
126
                    }
 
127
                }
 
128
            }
 
129
 
 
130
            String charSetName = getTextEncodingCharSet();
 
131
            if (charSetName.equals(TextEncoding.CHARSET_UTF_16))
 
132
            {
 
133
                charSetName = TextEncoding.CHARSET_UTF_16_ENCODING_FORMAT;
 
134
                CharsetEncoder encoder = Charset.forName(charSetName).newEncoder();
 
135
                //Note remember LE BOM is ff fe but this is handled by encoder Unicode char is fe ff
 
136
                ByteBuffer bb = encoder.encode(CharBuffer.wrap('\ufeff' +  value));
 
137
                data = new byte[bb.limit()];
 
138
                bb.get(data, 0, bb.limit());
 
139
 
 
140
            }
 
141
            else
 
142
            {
 
143
                 CharsetEncoder encoder = Charset.forName(charSetName).newEncoder();
 
144
                ByteBuffer bb = encoder.encode(CharBuffer.wrap( value));
 
145
                data = new byte[bb.limit()];
 
146
                bb.get(data, 0, bb.limit());
 
147
            }
 
148
        }
 
149
        //Should never happen so if does throw a RuntimeException
 
150
        catch (CharacterCodingException ce)
 
151
        {
 
152
            logger.severe(ce.getMessage());
 
153
            throw new RuntimeException(ce);
 
154
        }
 
155
        setSize(data.length);
 
156
        return data;
 
157
    }
 
158
 
 
159
    /**
 
160
     * Get the text encoding being used.
 
161
     * <p/>
 
162
     * The text encoding is defined by the frame body that the text field belongs to.
 
163
     *
 
164
     * @return the text encoding charset
 
165
     */
 
166
    protected String getTextEncodingCharSet()
 
167
    {
 
168
        byte textEncoding = this.getBody().getTextEncoding();
 
169
        String charSetName = TextEncoding.getInstanceOf().getValueForId(textEncoding);
 
170
        logger.finest("text encoding:" + textEncoding + " charset:" + charSetName);
 
171
        return charSetName;
 
172
    }
 
173
 
 
174
    /**
 
175
     * Holds data
 
176
     *
 
177
      */
 
178
    public static class PartOfSetValue
 
179
    {
 
180
        private static final Pattern trackNoPatternWithTotalCount;
 
181
        private static final Pattern trackNoPattern;
 
182
 
 
183
        static
 
184
        {
 
185
            //Match track/total pattern allowing for extraneous nulls ectera at the end
 
186
            trackNoPatternWithTotalCount  = Pattern.compile("([0-9]+)/([0-9]+)(.*)", Pattern.CASE_INSENSITIVE);
 
187
            trackNoPattern                = Pattern.compile("([0-9]+)(.*)", Pattern.CASE_INSENSITIVE);
 
188
        }
 
189
 
 
190
        private static final String SEPARATOR = "/";
 
191
        private Integer count;
 
192
        private Integer total;
 
193
        private String  extra;   //Any extraneous info such as null chars
 
194
        public PartOfSetValue()
 
195
        {
 
196
 
 
197
        }
 
198
 
 
199
        /** When constructing from data
 
200
         *
 
201
         * @param value
 
202
         */
 
203
        public PartOfSetValue(String value)
 
204
        {
 
205
            
 
206
            Matcher m = trackNoPatternWithTotalCount.matcher(value);
 
207
            if (m.matches())
 
208
            {
 
209
                this.count = Integer.parseInt(m.group(1));
 
210
                this.total = Integer.parseInt(m.group(2));
 
211
                this.extra = m.group(3);
 
212
                return;
 
213
            }
 
214
 
 
215
            m = trackNoPattern.matcher(value);
 
216
            if (m.matches())
 
217
            {
 
218
                this.count = Integer.parseInt(m.group(1));
 
219
                this.extra = m.group(2);
 
220
            }
 
221
        }
 
222
 
 
223
        /**
 
224
         * Newly created
 
225
         *
 
226
         * @param count
 
227
         * @param total
 
228
         */
 
229
        public PartOfSetValue(Integer count,Integer total)
 
230
        {
 
231
            this.count = count;
 
232
            this.total = total;
 
233
        }
 
234
 
 
235
 
 
236
 
 
237
        public Integer getCount()
 
238
        {
 
239
            return count;
 
240
        }
 
241
 
 
242
        public Integer getTotal()
 
243
        {
 
244
            return total;
 
245
        }
 
246
 
 
247
        public void setCount(Integer count)
 
248
        {
 
249
            this.count=count;
 
250
        }
 
251
 
 
252
        public void setTotal(Integer total)
 
253
        {
 
254
            this.total=total;
 
255
 
 
256
        }
 
257
 
 
258
        public void setCount(String count)
 
259
        {
 
260
            try
 
261
            {
 
262
                this.count=Integer.parseInt(count);
 
263
            }
 
264
            catch(NumberFormatException nfe)
 
265
            {
 
266
 
 
267
            }
 
268
        }
 
269
 
 
270
        public void setTotal(String total)
 
271
        {
 
272
            try
 
273
            {
 
274
                this.total=Integer.parseInt(total);
 
275
            }
 
276
            catch(NumberFormatException nfe)
 
277
            {
 
278
 
 
279
            }
 
280
        }
 
281
 
 
282
        public String toString()
 
283
        {
 
284
            //Don't Pad
 
285
            StringBuffer sb = new StringBuffer();
 
286
            if(!TagOptionSingleton.getInstance().isPadNumbers())
 
287
            {
 
288
                if(count!=null)
 
289
                {
 
290
                    sb.append(count.intValue());
 
291
                }
 
292
                else if(total!=null)
 
293
                {
 
294
                    sb.append('0');
 
295
                }
 
296
                if(total!=null)
 
297
                {
 
298
                    sb.append(SEPARATOR).append(total);
 
299
                }
 
300
                if(extra!=null)
 
301
                {
 
302
                    sb.append(extra);
 
303
                }
 
304
            }
 
305
            else
 
306
            {
 
307
                if(count!=null)
 
308
                {
 
309
                    if(count>0 && count<10)
 
310
                    {
 
311
                        sb.append("0").append(count);
 
312
                    }
 
313
                    else
 
314
                    {
 
315
                        sb.append(count.intValue());
 
316
                    }
 
317
                }
 
318
                else if(total!=null)
 
319
                {
 
320
                    sb.append('0');
 
321
                }
 
322
                if(total!=null)
 
323
                {
 
324
                    if(total>0 && total<10)
 
325
                    {
 
326
                        sb.append(SEPARATOR + "0").append(total);
 
327
                    }
 
328
                    else
 
329
                    {
 
330
                        sb.append(SEPARATOR).append(total);
 
331
                    }
 
332
                }
 
333
                if(extra!=null)
 
334
                {
 
335
                    sb.append(extra);
 
336
                }
 
337
            }
 
338
            return sb.toString();
 
339
        }
 
340
 
 
341
 
 
342
        public boolean equals(Object obj)
 
343
        {
 
344
            if(obj==this)
 
345
            {
 
346
                return true;
 
347
            }
 
348
 
 
349
            if (!(obj instanceof PartOfSetValue))
 
350
            {
 
351
                return false;
 
352
            }
 
353
 
 
354
            PartOfSetValue that = (PartOfSetValue) obj;
 
355
 
 
356
            return
 
357
                  EqualsUtil.areEqual(getCount(), that.getCount()) &&
 
358
                  EqualsUtil.areEqual(getTotal(), that.getTotal());
 
359
        }
 
360
 
 
361
    }
 
362
 
 
363
 
 
364
    public PartOfSetValue getValue()
 
365
    {
 
366
        return (PartOfSetValue)value;
 
367
    }
 
368
 
 
369
    public String toString()
 
370
    {
 
371
        return value.toString();
 
372
    }
339
373
}
 
 
b'\\ No newline at end of file'