1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi.hotspot2.anqp;
18 
19 import android.text.TextUtils;
20 
21 import com.android.internal.annotations.VisibleForTesting;
22 import com.android.server.wifi.ByteBufferReader;
23 
24 import java.net.ProtocolException;
25 import java.nio.BufferUnderflowException;
26 import java.nio.ByteBuffer;
27 import java.nio.charset.StandardCharsets;
28 import java.util.Locale;
29 
30 /**
31  * A generic Internationalized name field used in the Operator Friendly Name ANQP element
32  * (see HS2.0 R2 Spec 4.2) and the Venue Name ANQP element (see 802.11-2012 8.4.4.4).
33  *
34  * Format:
35  *
36  * | Length | Language Code |   Name   |
37  *      1           3         variable
38  */
39 public class I18Name {
40     @VisibleForTesting
41     public static final int LANGUAGE_CODE_LENGTH = 3;
42 
43     @VisibleForTesting
44     public static final int MINIMUM_LENGTH = LANGUAGE_CODE_LENGTH;
45 
46     private final String mLanguage;
47     private final Locale mLocale;
48     private final String mText;
49 
50     @VisibleForTesting
I18Name(String language, Locale locale, String text)51     public I18Name(String language, Locale locale, String text) {
52         mLanguage = language;
53         mLocale = locale;
54         mText = text;
55     }
56 
57     /**
58      * Parse a I18Name from the given buffer.
59      *
60      * @param payload The byte buffer to read from
61      * @return {@link I18Name}
62      * @throws BufferUnderflowException
63      * @throws ProtocolException
64      */
parse(ByteBuffer payload)65     public static I18Name parse(ByteBuffer payload) throws ProtocolException {
66         // Retrieve the length field.
67         int length = payload.get() & 0xFF;
68 
69         // Check for the minimum required length.
70         if (length < MINIMUM_LENGTH) {
71             throw new ProtocolException("Invalid length: " + length);
72         }
73 
74         // Read the language string.
75         String language = ByteBufferReader.readString(
76                 payload, LANGUAGE_CODE_LENGTH, StandardCharsets.US_ASCII).trim();
77         Locale locale;
78         try {
79             // The language code is a two or three character language code defined in ISO-639.
80             locale = new Locale.Builder().setLanguage(language).build();
81         } catch (Exception e) {
82             throw new ProtocolException("Invalid language: " + language);
83         }
84         // Read the text string.
85         String text = ByteBufferReader.readString(payload, length - LANGUAGE_CODE_LENGTH,
86                 StandardCharsets.UTF_8);
87         return new I18Name(language, locale, text);
88     }
89 
getLanguage()90     public String getLanguage() {
91         return mLanguage;
92     }
93 
getLocale()94     public Locale getLocale() {
95         return mLocale;
96     }
97 
getText()98     public String getText() {
99         return mText;
100     }
101 
102     @Override
equals(Object thatObject)103     public boolean equals(Object thatObject) {
104         if (this == thatObject) {
105             return true;
106         }
107         if (!(thatObject instanceof I18Name)) {
108             return false;
109         }
110 
111         I18Name that = (I18Name) thatObject;
112         return TextUtils.equals(mLanguage, that.mLanguage)
113                 && TextUtils.equals(mText, that.mText);
114     }
115 
116     @Override
hashCode()117     public int hashCode() {
118         int result = mLanguage.hashCode();
119         result = 31 * result + mText.hashCode();
120         return result;
121     }
122 
123     @Override
toString()124     public String toString() {
125         return mText + ':' + mLocale.getLanguage();
126     }
127 }
128