1 /*
2  * String values functions
3  *
4  * Copyright (C) 2011-2019, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <memory.h>
24 #include <types.h>
25 
26 #include "libwrc_data_descriptor.h"
27 #include "libwrc_definitions.h"
28 #include "libwrc_io_handle.h"
29 #include "libwrc_language_entry.h"
30 #include "libwrc_libbfio.h"
31 #include "libwrc_libcerror.h"
32 #include "libwrc_libcnotify.h"
33 #include "libwrc_libfvalue.h"
34 #include "libwrc_string_values.h"
35 
36 /* Reads string values
37  * Returns 1 if successful or -1 on error
38  */
libwrc_string_values_read(libwrc_language_entry_t * language_entry,libwrc_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,uint32_t identifier,libwrc_data_descriptor_t * data_descriptor,libcerror_error_t ** error)39 int libwrc_string_values_read(
40      libwrc_language_entry_t *language_entry,
41      libwrc_io_handle_t *io_handle,
42      libbfio_handle_t *file_io_handle,
43      uint32_t identifier,
44      libwrc_data_descriptor_t *data_descriptor,
45      libcerror_error_t **error )
46 {
47 	libfvalue_value_t *string_value = NULL;
48 	uint8_t *resource_data          = NULL;
49 	uint8_t *string_resource_data   = NULL;
50 	static char *function           = "libwrc_string_values_read";
51 	off64_t file_offset             = 0;
52 	size_t resource_data_size       = 0;
53 	ssize_t read_count              = 0;
54 	uint32_t string_identifier      = 0;
55 	uint32_t string_index           = 0;
56 	uint32_t string_size            = 0;
57 	int value_index                 = 0;
58 
59 	if( language_entry == NULL )
60 	{
61 		libcerror_error_set(
62 		 error,
63 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
64 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
65 		 "%s: invalid language entry.",
66 		 function );
67 
68 		return( -1 );
69 	}
70 	if( io_handle == NULL )
71 	{
72 		libcerror_error_set(
73 		 error,
74 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
75 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
76 		 "%s: invalid IO handle.",
77 		 function );
78 
79 		return( -1 );
80 	}
81 	if( data_descriptor == NULL )
82 	{
83 		libcerror_error_set(
84 		 error,
85 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
86 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
87 		 "%s: invalid data descriptor.",
88 		 function );
89 
90 		return( -1 );
91 	}
92 	file_offset = data_descriptor->virtual_address
93 	            - io_handle->virtual_address;
94 
95 	if( libbfio_handle_seek_offset(
96 	     file_io_handle,
97 	     file_offset,
98 	     SEEK_SET,
99 	     error ) == -1 )
100 	{
101 		libcerror_error_set(
102 		 error,
103 		 LIBCERROR_ERROR_DOMAIN_IO,
104 		 LIBCERROR_IO_ERROR_SEEK_FAILED,
105 		 "%s: unable to seek resource data offset: %" PRIi64 ".",
106 		 function,
107 		 file_offset );
108 
109 		goto on_error;
110 	}
111 	resource_data_size = (size_t) data_descriptor->size;
112 
113 	resource_data = (uint8_t *) memory_allocate(
114 	                             sizeof( uint8_t ) * resource_data_size );
115 
116 	if( resource_data == NULL )
117 	{
118 		libcerror_error_set(
119 		 error,
120 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
121 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
122 		 "%s: unable to create resource data.",
123 		 function );
124 
125 		goto on_error;
126 	}
127 	read_count = libbfio_handle_read_buffer(
128 	              file_io_handle,
129 	              resource_data,
130 	              resource_data_size,
131 	              error );
132 
133 	if( read_count != (ssize_t) resource_data_size )
134 	{
135 		libcerror_error_set(
136 		 error,
137 		 LIBCERROR_ERROR_DOMAIN_IO,
138 		 LIBCERROR_IO_ERROR_READ_FAILED,
139 		 "%s: unable to read resource data.",
140 		 function );
141 
142 		goto on_error;
143 	}
144 	string_resource_data = resource_data;
145 
146 #if defined( HAVE_DEBUG_OUTPUT )
147 	if( libcnotify_verbose != 0 )
148 	{
149 		libcnotify_printf(
150 		 "%s: resource data:\n",
151 		 function );
152 		libcnotify_print_data(
153 		 string_resource_data,
154 		 resource_data_size,
155 		 0 );
156 	}
157 #endif
158 	while( resource_data_size > 0 )
159 	{
160 		byte_stream_copy_to_uint16_little_endian(
161 		 string_resource_data,
162 		 string_size );
163 
164 		string_resource_data += sizeof( uint16_t );
165 		resource_data_size   -= sizeof( uint16_t );
166 
167 #if defined( HAVE_DEBUG_OUTPUT )
168 		if( libcnotify_verbose != 0 )
169 		{
170 			libcnotify_printf(
171 			 "%s: string: %02" PRIu32 " length\t\t\t\t: %" PRIu32 "\n",
172 			 function,
173 			 string_index,
174 			 string_size );
175 		}
176 #endif
177 		if( string_size > 0 )
178 		{
179 			string_identifier = ( identifier << 4 ) | string_index;
180 
181 			string_size *= 2;
182 
183 			if( string_size > resource_data_size )
184 			{
185 				libcerror_error_set(
186 				 error,
187 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
188 				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
189 				 "%s: string size value out of bound.",
190 				 function );
191 
192 				goto on_error;
193 			}
194 			if( libfvalue_value_type_initialize(
195 			     &string_value,
196 			     LIBFVALUE_VALUE_TYPE_STRING_UTF16,
197 			     error ) != 1 )
198 			{
199 				libcerror_error_set(
200 				 error,
201 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
202 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
203 				 "%s: unable to create string value.",
204 				 function );
205 
206 				goto on_error;
207 			}
208 			if( libfvalue_value_set_identifier(
209 			     string_value,
210 			     (uint8_t *) &string_identifier,
211 			     4,
212 			     LIBFVALUE_VALUE_IDENTIFIER_FLAG_MANAGED,
213 			     error ) != 1 )
214 			{
215 				libcerror_error_set(
216 				 error,
217 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
218 				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
219 				 "%s: unable to set identifier of string value.",
220 				 function );
221 
222 				goto on_error;
223 			}
224 #if defined( HAVE_DEBUG_OUTPUT )
225 			if( libcnotify_verbose != 0 )
226 			{
227 				libcnotify_printf(
228 				 "%s: string: %02" PRIu32 " data:\n",
229 				 function,
230 				 string_index );
231 				libcnotify_print_data(
232 				 string_resource_data,
233 				 (size_t) string_size,
234 				 0 );
235 			}
236 #endif
237 			if( libfvalue_value_set_data(
238 			     string_value,
239 			     string_resource_data,
240 			     (size_t) string_size,
241 			     LIBFVALUE_CODEPAGE_UTF16_LITTLE_ENDIAN,
242 			     LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
243 			     error ) != 1 )
244 			{
245 				libcerror_error_set(
246 				 error,
247 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
248 				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
249 				 "%s: unable to set data of string value.",
250 				 function );
251 
252 				goto on_error;
253 			}
254 #if defined( HAVE_DEBUG_OUTPUT )
255 			if( libcnotify_verbose != 0 )
256 			{
257 				libcnotify_printf(
258 				 "%s: string: %02" PRIu32 " value\t\t\t\t: ",
259 				 function,
260 				 string_index );
261 
262 				if( libfvalue_value_print(
263 				     string_value,
264 				     0,
265 				     0,
266 				     error ) != 1 )
267 				{
268 					libcerror_error_set(
269 					 error,
270 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
271 					 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
272 					 "%s: unable to print string value.",
273 					 function );
274 
275 					goto on_error;
276 				}
277 				libcnotify_printf(
278 				 "\n" );
279 			}
280 #endif
281 			string_resource_data += (size_t) string_size;
282 			resource_data_size   -= (size_t) string_size;
283 
284 			if( libwrc_language_entry_append_value(
285 			     language_entry,
286 			     &value_index,
287 			     (intptr_t *) string_value,
288 			     error ) != 1 )
289 			{
290 				libcerror_error_set(
291 				 error,
292 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
293 				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
294 				 "%s: unable to append string value.",
295 				 function );
296 
297 				goto on_error;
298 			}
299 			string_value = NULL;
300 		}
301 #if defined( HAVE_DEBUG_OUTPUT )
302 		else if( libcnotify_verbose != 0 )
303 		{
304 			libcnotify_printf(
305 			 "\n" );
306 		}
307 #endif
308 		string_index++;
309 	}
310 	memory_free(
311 	 resource_data );
312 
313 /* TODO validate if number of strings is 16 ? */
314 
315 	return( 1 );
316 
317 on_error:
318 	if( string_value != NULL )
319 	{
320 		libfvalue_value_free(
321 		 &string_value,
322 		 NULL );
323 	}
324 	if( resource_data != NULL )
325 	{
326 		memory_free(
327 		 resource_data );
328 	}
329 	return( -1 );
330 }
331 
332