1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 * The DataIO module provides a system independent (endianess and
16 * sizeof(int) independent) way to write and read data. It supports
17 * multiple datas which are collected in a buffer. It provides
18 * recognition of error cases like "not enough space" or "not enough
23 #include <fc_config.h>
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
49 #include "bitvector.h"
50 #include "capability.h"
58 #include "requirements.h"
64 static bool get_conv(char *dst
, size_t ndst
, const char *src
,
67 static DIO_PUT_CONV_FUN put_conv_callback
= NULL
;
68 static DIO_GET_CONV_FUN get_conv_callback
= get_conv
;
70 /**************************************************************************
71 Sets string conversion callback to be used when putting text.
72 **************************************************************************/
73 void dio_set_put_conv_callback(DIO_PUT_CONV_FUN fun
)
75 put_conv_callback
= fun
;
78 /**************************************************************************
79 Returns FALSE if the destination isn't large enough or the source was
80 bad. This is default get_conv_callback.
81 **************************************************************************/
82 static bool get_conv(char *dst
, size_t ndst
, const char *src
,
85 size_t len
= nsrc
; /* length to copy, not including null */
88 if (ndst
> 0 && len
>= ndst
) {
93 memcpy(dst
, src
, len
);
99 /**************************************************************************
100 Sets string conversion callback to use when getting text.
101 **************************************************************************/
102 void dio_set_get_conv_callback(DIO_GET_CONV_FUN fun
)
104 get_conv_callback
= fun
;
107 /**************************************************************************
108 Returns TRUE iff the output has size bytes available.
109 **************************************************************************/
110 static bool enough_space(struct data_out
*dout
, size_t size
)
112 if (dout
->current
+ size
> dout
->dest_size
) {
113 dout
->too_short
= TRUE
;
116 dout
->used
= MAX(dout
->used
, dout
->current
+ size
);
121 /**************************************************************************
122 Returns TRUE iff the input contains size unread bytes.
123 **************************************************************************/
124 static bool enough_data(struct data_in
*din
, size_t size
)
126 return dio_input_remaining(din
) >= size
;
129 /**************************************************************************
130 Initializes the output to the given output buffer and the given
132 **************************************************************************/
133 void dio_output_init(struct data_out
*dout
, void *destination
,
136 dout
->dest
= destination
;
137 dout
->dest_size
= dest_size
;
140 dout
->too_short
= FALSE
;
143 /**************************************************************************
144 Return the maximum number of bytes used.
145 **************************************************************************/
146 size_t dio_output_used(struct data_out
*dout
)
151 /**************************************************************************
152 Rewinds the stream so that the put-functions start from the
154 **************************************************************************/
155 void dio_output_rewind(struct data_out
*dout
)
160 /**************************************************************************
161 Initializes the input to the given input buffer and the given
162 number of valid input bytes.
163 **************************************************************************/
164 void dio_input_init(struct data_in
*din
, const void *src
, size_t src_size
)
167 din
->src_size
= src_size
;
171 /**************************************************************************
172 Rewinds the stream so that the get-functions start from the
174 **************************************************************************/
175 void dio_input_rewind(struct data_in
*din
)
180 /**************************************************************************
181 Return the number of unread bytes.
182 **************************************************************************/
183 size_t dio_input_remaining(struct data_in
*din
)
185 return din
->src_size
- din
->current
;
188 /**************************************************************************
189 Return the size of the data_type in bytes.
190 **************************************************************************/
191 size_t data_type_size(enum data_type type
)
207 fc_assert_msg(FALSE
, "data_type %d not handled.", type
);
211 /**************************************************************************
213 **************************************************************************/
214 bool dio_input_skip(struct data_in
*din
, size_t size
)
216 if (enough_data(din
, size
)) {
217 din
->current
+= size
;
224 /**************************************************************************
225 Insert value using 8 bits. May overflow.
226 **************************************************************************/
227 void dio_put_uint8(struct data_out
*dout
, int value
)
229 if (value
< 0x00 || 0xff < value
) {
230 log_error("Trying to put %d into 8 bits", value
);
233 if (enough_space(dout
, 1)) {
236 FC_STATIC_ASSERT(sizeof(x
) == 1, uint8_not_1_byte
);
237 memcpy(ADD_TO_POINTER(dout
->dest
, dout
->current
), &x
, 1);
242 /**************************************************************************
243 Insert value using 16 bits. May overflow.
244 **************************************************************************/
245 void dio_put_uint16(struct data_out
*dout
, int value
)
247 if (value
< 0x0000 || 0xffff < value
) {
248 log_error("Trying to put %d into 16 bits", value
);
251 if (enough_space(dout
, 2)) {
252 uint16_t x
= htons(value
);
254 FC_STATIC_ASSERT(sizeof(x
) == 2, uint16_not_2_bytes
);
255 memcpy(ADD_TO_POINTER(dout
->dest
, dout
->current
), &x
, 2);
260 /**************************************************************************
261 Insert value using 32 bits. May overflow.
262 **************************************************************************/
263 void dio_put_uint32(struct data_out
*dout
, int value
)
265 if (sizeof(value
) > 4 && (value
< 0x00000000 || 0xffffffff < value
)) {
266 log_error("Trying to put %d into 32 bits", value
);
269 if (enough_space(dout
, 4)) {
270 uint32_t x
= htonl(value
);
272 FC_STATIC_ASSERT(sizeof(x
) == 4, uint32_not_4_bytes
);
273 memcpy(ADD_TO_POINTER(dout
->dest
, dout
->current
), &x
, 4);
278 /**************************************************************************
279 Insert value using 'size' bits. May overflow.
280 **************************************************************************/
281 void dio_put_type(struct data_out
*dout
, enum data_type type
, int value
)
285 dio_put_uint8(dout
, value
);
288 dio_put_uint16(dout
, value
);
291 dio_put_uint32(dout
, value
);
294 dio_put_sint8(dout
, value
);
297 dio_put_sint16(dout
, value
);
300 dio_put_sint32(dout
, value
);
306 fc_assert_msg(FALSE
, "data_type %d not handled.", type
);
309 /**************************************************************************
310 Insert value using 8 bits. May overflow.
311 **************************************************************************/
312 void dio_put_sint8(struct data_out
*dout
, int value
)
314 dio_put_uint8(dout
, 0 <= value
? value
: value
+ 0x100);
317 /**************************************************************************
318 Insert value using 16 bits. May overflow.
319 **************************************************************************/
320 void dio_put_sint16(struct data_out
*dout
, int value
)
322 dio_put_uint16(dout
, 0 <= value
? value
: value
+ 0x10000);
325 /**************************************************************************
326 Insert value using 32 bits. May overflow.
327 **************************************************************************/
328 void dio_put_sint32(struct data_out
*dout
, int value
)
331 dio_put_uint32(dout
, value
);
333 dio_put_uint32(dout
, (0 <= value
? value
: value
+ 0x100000000));
337 /**************************************************************************
338 Insert value 0 or 1 using 8 bits.
339 **************************************************************************/
340 void dio_put_bool8(struct data_out
*dout
, bool value
)
342 if (value
!= TRUE
&& value
!= FALSE
) {
343 log_error("Trying to put a non-boolean: %d", (int) value
);
347 dio_put_uint8(dout
, value
? 1 : 0);
350 /**************************************************************************
351 Insert value 0 or 1 using 32 bits.
352 **************************************************************************/
353 void dio_put_bool32(struct data_out
*dout
, bool value
)
355 if (value
!= TRUE
&& value
!= FALSE
) {
356 log_error("Trying to put a non-boolean: %d", (int) value
);
360 dio_put_uint32(dout
, value
? 1 : 0);
363 /**************************************************************************
364 Insert a float number, which is multiplied by 'float_factor' before
365 being encoded into a uint32.
366 **************************************************************************/
367 void dio_put_float(struct data_out
*dout
, float value
, int float_factor
)
369 dio_put_uint32(dout
, value
* float_factor
);
372 /**************************************************************************
373 Insert number of values brefore stop_value using 8 bits. Then
374 insert values using 8 bits for each. stop_value is not required to
375 fit in 8 bits. Actual values may overflow.
376 **************************************************************************/
377 void dio_put_uint8_vec8(struct data_out
*dout
, int *values
, int stop_value
)
381 for (count
= 0; values
[count
] != stop_value
; count
++) {
385 if (enough_space(dout
, 1 + count
)) {
388 dio_put_uint8(dout
, count
);
390 for (i
= 0; i
< count
; i
++) {
391 dio_put_uint8(dout
, values
[i
]);
396 /**************************************************************************
397 Insert number of values brefore stop_value using 8 bits. Then
398 insert values using 16 bits for each. stop_value is not required to
399 fit in 16 bits. Actual values may overflow.
400 **************************************************************************/
401 void dio_put_uint16_vec8(struct data_out
*dout
, int *values
, int stop_value
)
405 for (count
= 0; values
[count
] != stop_value
; count
++) {
409 if (enough_space(dout
, 1 + 2 * count
)) {
412 dio_put_uint8(dout
, count
);
414 for (i
= 0; i
< count
; i
++) {
415 dio_put_uint16(dout
, values
[i
]);
420 /**************************************************************************
421 Insert block directly from memory.
422 **************************************************************************/
423 void dio_put_memory(struct data_out
*dout
, const void *value
, size_t size
)
425 if (enough_space(dout
, size
)) {
426 memcpy(ADD_TO_POINTER(dout
->dest
, dout
->current
), value
, size
);
427 dout
->current
+= size
;
431 /**************************************************************************
432 Insert NULL-terminated string. Conversion callback is used if set.
433 **************************************************************************/
434 void dio_put_string(struct data_out
*dout
, const char *value
)
436 if (put_conv_callback
) {
440 if ((buffer
= (*put_conv_callback
) (value
, &length
))) {
441 dio_put_memory(dout
, buffer
, length
+ 1);
445 dio_put_memory(dout
, value
, strlen(value
) + 1);
449 /**************************************************************************
450 Insert tech numbers from value array as 8 bit values until there is value
451 A_LAST or MAX_NUM_TECH_LIST tech numbers have been inserted.
452 **************************************************************************/
453 void dio_put_tech_list(struct data_out
*dout
, const int *value
)
457 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
458 dio_put_uint8(dout
, value
[i
]);
459 if (value
[i
] == A_LAST
) {
465 /**************************************************************************
466 Insert unit type numbers from value array as 8 bit values until there is
467 value U_LAST or MAX_NUM_UNIT_LIST numbers have been inserted.
468 **************************************************************************/
469 void dio_put_unit_list(struct data_out
*dout
, const int *value
)
473 for (i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
474 dio_put_uint8(dout
, value
[i
]);
475 if (value
[i
] == U_LAST
) {
481 /**************************************************************************
482 Insert building type numbers from value array as 8 bit values until there
483 is value B_LAST or MAX_NUM_BUILDING_LIST numbers have been inserted.
484 **************************************************************************/
485 void dio_put_building_list(struct data_out
*dout
, const int *value
)
489 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
490 dio_put_uint8(dout
, value
[i
]);
491 if (value
[i
] == B_LAST
) {
497 /**************************************************************************
498 Insert number of worklist items as 8 bit value and then insert
499 8 bit kind and 8 bit number for each worklist item.
500 **************************************************************************/
501 void dio_put_worklist(struct data_out
*dout
, const struct worklist
*pwl
)
503 int i
, length
= worklist_length(pwl
);
505 dio_put_uint8(dout
, length
);
506 for (i
= 0; i
< length
; i
++) {
507 const struct universal
*pcp
= &(pwl
->entries
[i
]);
509 dio_put_uint8(dout
, pcp
->kind
);
510 dio_put_uint8(dout
, universal_number(pcp
));
514 /**************************************************************************
515 Receive uint8 value to dest.
516 **************************************************************************/
517 bool dio_get_uint8(struct data_in
*din
, int *dest
)
521 FC_STATIC_ASSERT(sizeof(x
) == 1, uint8_not_byte
);
523 if (!enough_data(din
, 1)) {
524 log_packet("Packet too short to read 1 byte");
529 memcpy(&x
, ADD_TO_POINTER(din
->src
, din
->current
), 1);
535 /**************************************************************************
536 Receive uint16 value to dest.
537 **************************************************************************/
538 bool dio_get_uint16(struct data_in
*din
, int *dest
)
542 FC_STATIC_ASSERT(sizeof(x
) == 2, uint16_not_2_bytes
);
544 if (!enough_data(din
, 2)) {
545 log_packet("Packet too short to read 2 bytes");
550 memcpy(&x
, ADD_TO_POINTER(din
->src
, din
->current
), 2);
556 /**************************************************************************
557 Receive uint32 value to dest.
558 **************************************************************************/
559 bool dio_get_uint32(struct data_in
*din
, int *dest
)
563 FC_STATIC_ASSERT(sizeof(x
) == 4, uint32_not_4_bytes
);
565 if (!enough_data(din
, 4)) {
566 log_packet("Packet too short to read 4 bytes");
571 memcpy(&x
, ADD_TO_POINTER(din
->src
, din
->current
), 4);
577 /**************************************************************************
578 Receive value using 'size' bits to dest.
579 **************************************************************************/
580 bool dio_get_type(struct data_in
*din
, enum data_type type
, int *dest
)
584 return dio_get_uint8(din
, dest
);
586 return dio_get_uint16(din
, dest
);
588 return dio_get_uint32(din
, dest
);
590 return dio_get_sint8(din
, dest
);
592 return dio_get_sint16(din
, dest
);
594 return dio_get_sint32(din
, dest
);
599 fc_assert_msg(FALSE
, "data_type %d not handled.", type
);
603 /**************************************************************************
604 Take boolean value from 8 bits.
605 **************************************************************************/
606 bool dio_get_bool8(struct data_in
*din
, bool *dest
)
610 if (!dio_get_uint8(din
, &ival
)) {
614 if (ival
!= 0 && ival
!= 1) {
615 log_packet("Got a bad boolean: %d", ival
);
623 /**************************************************************************
624 Take boolean value from 32 bits.
625 **************************************************************************/
626 bool dio_get_bool32(struct data_in
*din
, bool * dest
)
630 if (!dio_get_uint32(din
, &ival
)) {
634 if (ival
!= 0 && ival
!= 1) {
635 log_packet("Got a bad boolean: %d", ival
);
643 /**************************************************************************
644 Get a float number, which have been multiplied by 'float_factor' and
645 encoded into a uint32 by dio_put_float().
646 **************************************************************************/
647 bool dio_get_float(struct data_in
*din
, float *dest
, int float_factor
)
651 if (!dio_get_uint32(din
, &ival
)) {
655 *dest
= (float) ival
/ float_factor
;
659 /**************************************************************************
660 Take value from 8 bits.
661 **************************************************************************/
662 bool dio_get_sint8(struct data_in
*din
, int *dest
)
666 if (!dio_get_uint8(din
, &tmp
)) {
677 /**************************************************************************
678 Take value from 16 bits.
679 **************************************************************************/
680 bool dio_get_sint16(struct data_in
*din
, int *dest
)
684 if (!dio_get_uint16(din
, &tmp
)) {
695 /**************************************************************************
696 Take value from 32 bits.
697 **************************************************************************/
698 bool dio_get_sint32(struct data_in
*din
, int *dest
)
702 if (!dio_get_uint32(din
, &tmp
)) {
707 if (tmp
> 0x7fffffff) {
716 /**************************************************************************
717 Take memory block directly.
718 **************************************************************************/
719 bool dio_get_memory(struct data_in
*din
, void *dest
, size_t dest_size
)
721 if (!enough_data(din
, dest_size
)) {
722 log_packet("Got too short memory");
726 memcpy(dest
, ADD_TO_POINTER(din
->src
, din
->current
), dest_size
);
727 din
->current
+= dest_size
;
731 /**************************************************************************
732 Take string. Conversion callback is used.
733 **************************************************************************/
734 bool dio_get_string(struct data_in
*din
, char *dest
, size_t max_dest_size
)
737 size_t offset
, remaining
;
739 fc_assert(max_dest_size
> 0);
741 if (!enough_data(din
, 1)) {
742 log_packet("Got a bad string");
746 remaining
= dio_input_remaining(din
);
747 c
= ADD_TO_POINTER(din
->src
, din
->current
);
749 /* avoid using strlen (or strcpy) on an (unsigned char*) --dwp */
750 for (offset
= 0; offset
< remaining
&& c
[offset
] != '\0'; offset
++) {
754 if (offset
>= remaining
) {
755 log_packet("Got a too short string");
759 if (!(*get_conv_callback
) (dest
, max_dest_size
, c
, offset
)) {
760 log_packet("Got a bad encoded string");
764 din
->current
+= offset
+ 1;
768 /**************************************************************************
769 Take tech numbers until A_LAST encountered, or MAX_NUM_TECH_LIST techs
771 **************************************************************************/
772 bool dio_get_tech_list(struct data_in
*din
, int *dest
)
776 for (i
= 0; i
< MAX_NUM_TECH_LIST
; i
++) {
777 if (!dio_get_uint8(din
, &dest
[i
])) {
778 log_packet("Got a too short tech list");
781 if (dest
[i
] == A_LAST
) {
786 for (; i
< MAX_NUM_TECH_LIST
; i
++) {
793 /**************************************************************************
794 Take unit type numbers until U_LAST encountered, or MAX_NUM_UNIT_LIST
796 **************************************************************************/
797 bool dio_get_unit_list(struct data_in
*din
, int *dest
)
801 for (i
= 0; i
< MAX_NUM_UNIT_LIST
; i
++) {
802 if (!dio_get_uint8(din
, &dest
[i
])) {
803 log_packet("Got a too short unit list");
806 if (dest
[i
] == U_LAST
) {
811 for (; i
< MAX_NUM_UNIT_LIST
; i
++) {
818 /**************************************************************************
819 Take building type numbers until B_LAST encountered, or
820 MAX_NUM_BUILDING_LIST types retrieved.
821 **************************************************************************/
822 bool dio_get_building_list(struct data_in
*din
, int *dest
)
826 for (i
= 0; i
< MAX_NUM_BUILDING_LIST
; i
++) {
827 if (!dio_get_uint8(din
, &dest
[i
])) {
828 log_packet("Got a too short building list");
831 if (dest
[i
] == B_LAST
) {
836 for (; i
< MAX_NUM_BUILDING_LIST
; i
++) {
843 /**************************************************************************
844 Take worklist item count and then kind and number for each item, and
845 put them to provided worklist.
846 **************************************************************************/
847 bool dio_get_worklist(struct data_in
*din
, struct worklist
*pwl
)
853 if (!dio_get_uint8(din
, &length
)) {
854 log_packet("Got a bad worklist");
858 for (i
= 0; i
< length
; i
++) {
862 if (!dio_get_uint8(din
, &kind
)
863 || !dio_get_uint8(din
, &identifier
)) {
864 log_packet("Got a too short worklist");
869 * FIXME: the value returned by universal_by_number() should be checked!
871 worklist_append(pwl
, universal_by_number(kind
, identifier
));
877 /**************************************************************************
878 Take vector of 8 bit values and insert stop_value after them. stop_value
879 does not need to fit in 8 bits.
880 **************************************************************************/
881 bool dio_get_uint8_vec8(struct data_in
*din
, int **values
, int stop_value
)
886 if (!dio_get_uint8(din
, &count
)) {
890 vec
= fc_calloc(count
+ 1, sizeof(*vec
));
891 for (inx
= 0; inx
< count
; inx
++) {
892 if (!dio_get_uint8(din
, vec
+ inx
)) {
897 vec
[inx
] = stop_value
;
903 /**************************************************************************
904 Receive vector of uint6 values.
905 **************************************************************************/
906 bool dio_get_uint16_vec8(struct data_in
*din
, int **values
, int stop_value
)
911 if (!dio_get_uint8(din
, &count
)) {
915 vec
= fc_calloc(count
+ 1, sizeof(*vec
));
916 for (inx
= 0; inx
< count
; inx
++) {
917 if (!dio_get_uint16(din
, vec
+ inx
)) {
922 vec
[inx
] = stop_value
;
928 /**************************************************************************
929 De-serialize a requirement.
930 **************************************************************************/
931 bool dio_get_requirement(struct data_in
*din
, struct requirement
*preq
)
933 int type
, range
, value
;
934 bool survives
, negated
;
936 if (!dio_get_uint8(din
, &type
)
937 || !dio_get_sint32(din
, &value
)
938 || !dio_get_uint8(din
, &range
)
939 || !dio_get_bool8(din
, &survives
)
940 || !dio_get_bool8(din
, &negated
)) {
941 log_packet("Got a bad requirement");
946 * FIXME: the value returned by req_from_values() should be checked!
948 *preq
= req_from_values(type
, range
, survives
, negated
, value
);
953 /**************************************************************************
954 Serialize a requirement.
955 **************************************************************************/
956 void dio_put_requirement(struct data_out
*dout
, const struct requirement
*preq
)
958 int type
, range
, value
;
959 bool survives
, negated
;
961 req_get_values(preq
, &type
, &range
, &survives
, &negated
, &value
);
963 dio_put_uint8(dout
, type
);
964 dio_put_sint32(dout
, value
);
965 dio_put_uint8(dout
, range
);
966 dio_put_bool8(dout
, survives
);
967 dio_put_bool8(dout
, negated
);