1 /*
2 * Copyright (c) 2002-2026 Gargoyle Software Inc.
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 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.htmlunit.util;
16
17 import java.io.File;
18 import java.io.IOException;
19 import java.io.ObjectInputStream;
20 import java.io.ObjectOutputStream;
21 import java.nio.charset.Charset;
22
23 /**
24 * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
25 *
26 * A holder for a key/value pair that represents a file to upload.
27 *
28 * @author Brad Clarke
29 * @author David D. Kilzer
30 * @author Mike Bowler
31 * @author Ahmed Ashour
32 * @author Ronald Brill
33 * @author Michael Lueck
34 */
35 public class KeyDataPair extends NameValuePair {
36
37 private final File fileObject_;
38 private final String fileName_;
39 private final String mimeType_;
40 private transient Charset charset_;
41 private byte[] data_;
42
43 /**
44 * Creates an instance.
45 *
46 * @param key the key
47 * @param file the file
48 * @param fileName the name of the file
49 * @param mimeType the MIME type
50 * @param charset the charset encoding name
51 */
52 public KeyDataPair(final String key, final File file, final String fileName,
53 final String mimeType, final String charset) {
54 this(key, file, fileName, mimeType, Charset.forName(charset));
55 }
56
57 /**
58 * Creates an instance.
59 *
60 * @param key the key
61 * @param file the file
62 * @param fileName the name of the file
63 * @param mimeType the MIME type
64 * @param charset the charset encoding
65 */
66 public KeyDataPair(final String key, final File file, final String fileName,
67 final String mimeType, final Charset charset) {
68 this(key,
69 (file == null) ? "" : file.getName(),
70 (file != null && file.exists()) ? file : null,
71 fileName,
72 mimeType,
73 charset,
74 null);
75 }
76
77 /**
78 * Private constructor setting all fields directly.
79 *
80 * @param name passed as the name to the super constructor
81 * @param value passed as the value to the super constructor
82 * @param file the file, may be {@code null}
83 * @param fileName the filename, may be {@code null}
84 * @param mimeType the MIME type, may be {@code null}
85 * @param charset the charset, may be {@code null}
86 * @param data the in-memory file data, may be {@code null}
87 */
88 private KeyDataPair(final String name, final String value, final File file,
89 final String fileName, final String mimeType, final Charset charset,
90 final byte[] data) {
91 super(name, value);
92
93 fileObject_ = file;
94 fileName_ = fileName;
95
96 mimeType_ = mimeType;
97 charset_ = charset;
98
99 data_ = data;
100 }
101
102 /**
103 * {@inheritDoc}
104 */
105 @Override
106 @SuppressWarnings("PMD.UselessOverridingMethod")
107 public boolean equals(final Object object) {
108 // this is overwritten to make FindBugs happy
109 // and to make it clear, that we really want to have
110 // the same equals semantic like our parent class
111 return super.equals(object);
112 }
113
114 /**
115 * {@inheritDoc}
116 */
117 @Override
118 @SuppressWarnings("PMD.UselessOverridingMethod")
119 public int hashCode() {
120 // this is overwritten to make FindBugs happy
121 // and to make it clear, that we really want to have
122 // the same hashCode as our parent class
123 return super.hashCode();
124 }
125
126 /**
127 * Returns the {@link File} object if the file exists, otherwise {@code null}.
128 *
129 * @return the file, or {@code null} if it does not exist
130 */
131 public File getFile() {
132 return fileObject_;
133 }
134
135 /**
136 * Returns the file name.
137 *
138 * @return the file name
139 */
140 public String getFileName() {
141 return fileName_;
142 }
143
144 /**
145 * Returns the charset encoding for this file upload.
146 *
147 * @return the charset
148 */
149 public Charset getCharset() {
150 return charset_;
151 }
152
153 /**
154 * Returns the MIME type for this file upload.
155 *
156 * @return the MIME type
157 */
158 public String getMimeType() {
159 return mimeType_;
160 }
161
162 /**
163 * Returns the in-memory data assigned to this file value,
164 * or {@code null} if the actual file content should be used.
165 *
166 * @return the in-memory data, or {@code null}
167 */
168 public byte[] getData() {
169 return data_;
170 }
171
172 /**
173 * Sets the in-memory data for this file value.
174 * If not set, the file content will be used.
175 *
176 * @param data the byte array with file data
177 */
178 public void setData(final byte[] data) {
179 data_ = data;
180 }
181
182 private void writeObject(final ObjectOutputStream oos) throws IOException {
183 oos.defaultWriteObject();
184 oos.writeObject(charset_ == null ? null : charset_.name());
185 }
186
187 private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
188 ois.defaultReadObject();
189 final String charsetName = (String) ois.readObject();
190 if (charsetName != null) {
191 charset_ = Charset.forName(charsetName);
192 }
193 }
194
195 /**
196 * {@inheritDoc}
197 *
198 * Specialization of the inherited method that copies all fields
199 * and ensures the value in the base class is not {@code null}.
200 */
201 @Override
202 public KeyDataPair normalized() {
203 return new KeyDataPair(
204 this.getName(),
205 this.getValue(),
206 this.fileObject_,
207 this.fileName_,
208 this.mimeType_,
209 this.charset_,
210 this.data_);
211 }
212 }