FastCdr.cpp
Go to the documentation of this file.
1 // Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://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 #include <fastcdr/FastCdr.h>
17 #include <string.h>
18 
19 using namespace eprosima::fastcdr;
20 using namespace ::exception;
21 
23  const FastCdr& fastcdr)
24  : current_position_(fastcdr.current_position_)
25 {
26 }
27 
29  const state& current_state)
30  : current_position_(current_state.current_position_)
31 {
32 }
33 
35  FastBuffer& cdr_buffer)
36  : cdr_buffer_(cdr_buffer)
37  , current_position_(cdr_buffer.begin())
38  , last_position_(cdr_buffer.end())
39 {
40 }
41 
43  size_t num_bytes)
44 {
45  bool ret_value = false;
46 
47  if (((last_position_ - current_position_) >= num_bytes) || resize(num_bytes))
48  {
49  current_position_ += num_bytes;
50  ret_value = true;
51  }
52 
53  return ret_value;
54 }
55 
57 {
58  return &current_position_;
59 }
60 
62 {
63  return FastCdr::state(*this);
64 }
65 
67  FastCdr::state& current_state)
68 {
69  current_position_ >> current_state.current_position_;
70 }
71 
73 {
75 }
76 
78  size_t min_size_inc)
79 {
80  if (cdr_buffer_.resize(min_size_inc))
81  {
84  return true;
85  }
86 
87  return false;
88 }
89 
91  const bool bool_t)
92 {
93  uint8_t value = 0;
94 
95  if (((last_position_ - current_position_) >= sizeof(uint8_t)) || resize(sizeof(uint8_t)))
96  {
97  if (bool_t)
98  {
99  value = 1;
100  }
101  current_position_++ << value;
102 
103  return *this;
104  }
105 
107 }
108 
110  const char* string_t)
111 {
112  uint32_t length = 0;
113 
114  if (string_t != nullptr)
115  {
116  length = size_to_uint32(strlen(string_t)) + 1;
117  }
118 
119  if (length > 0)
120  {
121  FastCdr::state state_before_error(*this);
122  serialize(length);
123 
124  if (((last_position_ - current_position_) >= length) || resize(length))
125  {
126  current_position_.memcopy(string_t, length);
127  current_position_ += length;
128  }
129  else
130  {
131  set_state(state_before_error);
133  }
134  }
135  else
136  {
137  serialize(length);
138  }
139 
140  return *this;
141 }
142 
144  const wchar_t* string_t)
145 {
146  uint32_t bytes_length = 0;
147  size_t wstrlen = 0;
148 
149  if (string_t != nullptr)
150  {
151  wstrlen = wcslen(string_t);
152  bytes_length = size_to_uint32(wstrlen * 4);
153  }
154 
155  if (bytes_length > 0)
156  {
157  FastCdr::state state_(*this);
158  serialize(size_to_uint32(wstrlen));
159 
160  if (((last_position_ - current_position_) >= bytes_length) || resize(bytes_length))
161  {
162 #if defined(_WIN32)
163  serialize_array(string_t, wstrlen);
164 #else
165  current_position_.memcopy(string_t, bytes_length);
166  current_position_ += bytes_length; // size on bytes
167 #endif // if defined(_WIN32)
168  }
169  else
170  {
171  set_state(state_);
173  }
174  }
175  else
176  {
177  serialize(bytes_length);
178  }
179 
180  return *this;
181 }
182 
184  const bool* bool_t,
185  size_t num_elements)
186 {
187  size_t total_size = sizeof(*bool_t) * num_elements;
188 
189  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
190  {
191  for (size_t count = 0; count < num_elements; ++count)
192  {
193  uint8_t value = 0;
194 
195  if (bool_t[count])
196  {
197  value = 1;
198  }
199  current_position_++ << value;
200  }
201 
202  return *this;
203  }
204 
206 }
207 
209  const char* char_t,
210  size_t num_elements)
211 {
212  size_t total_size = sizeof(*char_t) * num_elements;
213 
214  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
215  {
216  current_position_.memcopy(char_t, total_size);
217  current_position_ += total_size;
218  return *this;
219  }
220 
222 }
223 
225  const int16_t* short_t,
226  size_t num_elements)
227 {
228  size_t total_size = sizeof(*short_t) * num_elements;
229 
230  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
231  {
232  current_position_.memcopy(short_t, total_size);
233  current_position_ += total_size;
234 
235  return *this;
236  }
237 
239 }
240 
242  const int32_t* long_t,
243  size_t num_elements)
244 {
245  size_t total_size = sizeof(*long_t) * num_elements;
246 
247  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
248  {
249  current_position_.memcopy(long_t, total_size);
250  current_position_ += total_size;
251 
252  return *this;
253  }
254 
256 }
257 
259  const wchar_t* wchar,
260  size_t num_elements)
261 {
262  for (size_t count = 0; count < num_elements; ++count)
263  {
264  serialize(wchar[count]);
265  }
266  return *this;
267 }
268 
270  const int64_t* longlong_t,
271  size_t num_elements)
272 {
273  size_t total_size = sizeof(*longlong_t) * num_elements;
274 
275  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
276  {
277  current_position_.memcopy(longlong_t, total_size);
278  current_position_ += total_size;
279 
280  return *this;
281  }
282 
284 }
285 
287  const float* float_t,
288  size_t num_elements)
289 {
290  size_t total_size = sizeof(*float_t) * num_elements;
291 
292  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
293  {
294  current_position_.memcopy(float_t, total_size);
295  current_position_ += total_size;
296 
297  return *this;
298  }
299 
301 }
302 
304  const double* double_t,
305  size_t num_elements)
306 {
307  size_t total_size = sizeof(*double_t) * num_elements;
308 
309  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
310  {
311  current_position_.memcopy(double_t, total_size);
312  current_position_ += total_size;
313 
314  return *this;
315  }
316 
318 }
319 
321  const long double* ldouble_t,
322  size_t num_elements)
323 {
324  size_t total_size = 16 * num_elements;
325 
326  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
327  {
328 #if FASTCDR_HAVE_FLOAT128 && FASTCDR_SIZEOF_LONG_DOUBLE < 16
329  for (size_t idx = 0; idx < num_elements; ++idx)
330  {
331  __float128 tmp = ldouble_t[idx];
332  current_position_ << tmp;
333  current_position_ += 16;
334  }
335 #else
336 #if FASTCDR_SIZEOF_LONG_DOUBLE == 16
337  current_position_.memcopy(ldouble_t, total_size);
338  current_position_ += total_size;
339 #else
340 #if FASTCDR_SIZEOF_LONG_DOUBLE == 8
341  for (size_t idx = 0; idx < num_elements; ++idx)
342  {
343  current_position_ << static_cast<long double>(0);
344  current_position_ += 8;
345  current_position_ << ldouble_t[idx];
346  current_position_ += 8;
347  }
348 #else
349 #error unsupported long double type and no __float128 available
350 #endif // FASTCDR_SIZEOF_LONG_DOUBLE == 8
351 #endif // FASTCDR_SIZEOF_LONG_DOUBLE == 16
352 #endif // FASTCDR_HAVE_FLOAT128 && FASTCDR_SIZEOF_LONG_DOUBLE < 16
353 
354  return *this;
355  }
356 
358 }
359 
361  bool& bool_t)
362 {
363  uint8_t value = 0;
364 
365  if ((last_position_ - current_position_) >= sizeof(uint8_t))
366  {
367  current_position_++ >> value;
368 
369  if (value == 1)
370  {
371  bool_t = true;
372  return *this;
373  }
374  else if (value == 0)
375  {
376  bool_t = false;
377  return *this;
378  }
379 
380  throw BadParamException("Got unexpected byte value in deserialize for bool (expected 0 or 1)");
381  }
382 
384 }
385 
387  char*& string_t)
388 {
389  uint32_t length = 0;
390  FastCdr::state state_before_error(*this);
391 
392  deserialize(length);
393 
394  if (length == 0)
395  {
396  string_t = NULL;
397  return *this;
398  }
399  else if ((last_position_ - current_position_) >= length)
400  {
401  // Allocate memory.
402  string_t =
403  reinterpret_cast<char*>(calloc(length + ((&current_position_)[length - 1] == '\0' ? 0 : 1),
404  sizeof(char)));
405  memcpy(string_t, &current_position_, length);
406  current_position_ += length;
407  return *this;
408  }
409 
410  set_state(state_before_error);
412 }
413 
415  wchar_t*& string_t)
416 {
417  uint32_t length = 0;
418  FastCdr::state state_before_error(*this);
419 
420  deserialize(length);
421 
422  if (length == 0)
423  {
424  string_t = NULL;
425  return *this;
426  }
427  else if ((last_position_ - current_position_) >= length)
428  {
429  // Allocate memory.
430  string_t = reinterpret_cast<wchar_t*>(calloc(length + 1, sizeof(wchar_t))); // WStrings never serialize terminating zero
431 
432 #if defined(_WIN32)
433  for (size_t idx = 0; idx < length; ++idx)
434  {
435  uint32_t temp;
436  current_position_ >> temp;
437  string_t[idx] = static_cast<wchar_t>(temp);
438  current_position_ += 4;
439  }
440 #else
441  memcpy(string_t, &current_position_, length * sizeof(wchar_t));
442  current_position_ += length * sizeof(wchar_t);
443 #endif // if defined(_WIN32)
444 
445  return *this;
446  }
447 
448  set_state(state_before_error);
450 }
451 
453  uint32_t& length)
454 {
455  const char* ret_value = "";
456  state state_before_error(*this);
457 
458  *this >> length;
459 
460  if (length == 0)
461  {
462  return ret_value;
463  }
464  else if ((last_position_ - current_position_) >= length)
465  {
466  ret_value = &current_position_;
467  current_position_ += length;
468  if (ret_value[length - 1] == '\0')
469  {
470  --length;
471  }
472  return ret_value;
473  }
474 
475  set_state(state_before_error);
478 }
479 
481  uint32_t& length)
482 {
483  std::wstring ret_value = L"";
484  state state_(*this);
485 
486  *this >> length;
487  uint32_t bytes_length = length * 4;
488 
489  if (bytes_length == 0)
490  {
491  return ret_value;
492  }
493  else if ((last_position_ - current_position_) >= bytes_length)
494  {
495 
496  ret_value.resize(length);
497  deserialize_array(const_cast<wchar_t*>(ret_value.c_str()), length);
498  if (ret_value[length - 1] == L'\0')
499  {
500  --length;
501  ret_value.erase(length);
502  }
503  return ret_value;
504  }
505 
506  set_state(state_);
509 }
510 
512  bool* bool_t,
513  size_t num_elements)
514 {
515  size_t total_size = sizeof(*bool_t) * num_elements;
516 
517  if ((last_position_ - current_position_) >= total_size)
518  {
519  for (size_t count = 0; count < num_elements; ++count)
520  {
521  uint8_t value = 0;
522  current_position_++ >> value;
523 
524  if (value == 1)
525  {
526  bool_t[count] = true;
527  }
528  else if (value == 0)
529  {
530  bool_t[count] = false;
531  }
532  }
533 
534  return *this;
535  }
536 
538 }
539 
541  char* char_t,
542  size_t num_elements)
543 {
544  size_t total_size = sizeof(*char_t) * num_elements;
545 
546  if ((last_position_ - current_position_) >= total_size)
547  {
548  current_position_.rmemcopy(char_t, total_size);
549  current_position_ += total_size;
550  return *this;
551  }
552 
554 }
555 
557  int16_t* short_t,
558  size_t num_elements)
559 {
560  size_t total_size = sizeof(*short_t) * num_elements;
561 
562  if ((last_position_ - current_position_) >= total_size)
563  {
564  current_position_.rmemcopy(short_t, total_size);
565  current_position_ += total_size;
566 
567  return *this;
568  }
569 
571 }
572 
574  int32_t* long_t,
575  size_t num_elements)
576 {
577  size_t total_size = sizeof(*long_t) * num_elements;
578 
579  if ((last_position_ - current_position_) >= total_size)
580  {
581  current_position_.rmemcopy(long_t, total_size);
582  current_position_ += total_size;
583 
584  return *this;
585  }
586 
588 }
589 
591  wchar_t* wchar,
592  size_t num_elements)
593 {
594  uint32_t value = 0;
595  for (size_t count = 0; count < num_elements; ++count)
596  {
597  deserialize(value);
598  wchar[count] = static_cast<wchar_t>(value);
599  }
600  return *this;
601 }
602 
604  int64_t* longlong_t,
605  size_t num_elements)
606 {
607  size_t total_size = sizeof(*longlong_t) * num_elements;
608 
609  if ((last_position_ - current_position_) >= total_size)
610  {
611  current_position_.rmemcopy(longlong_t, total_size);
612  current_position_ += total_size;
613 
614  return *this;
615  }
616 
618 }
619 
621  float* float_t,
622  size_t num_elements)
623 {
624  size_t total_size = sizeof(*float_t) * num_elements;
625 
626  if ((last_position_ - current_position_) >= total_size)
627  {
628  current_position_.rmemcopy(float_t, total_size);
629  current_position_ += total_size;
630 
631  return *this;
632  }
633 
635 }
636 
638  double* double_t,
639  size_t num_elements)
640 {
641  size_t total_size = sizeof(*double_t) * num_elements;
642 
643  if ((last_position_ - current_position_) >= total_size)
644  {
645  current_position_.rmemcopy(double_t, total_size);
646  current_position_ += total_size;
647 
648  return *this;
649  }
650 
652 }
653 
655  long double* ldouble_t,
656  size_t num_elements)
657 {
658  size_t total_size = 16 * num_elements;
659 
660  if ((last_position_ - current_position_) >= total_size)
661  {
662 #if FASTCDR_HAVE_FLOAT128 && FASTCDR_SIZEOF_LONG_DOUBLE < 16
663  for (size_t idx = 0; idx < num_elements; ++idx)
664  {
665  __float128 tmp;
666  current_position_ >> tmp;
667  current_position_ += 16;
668  ldouble_t[idx] = static_cast<long double>(tmp);
669  }
670 #else
671 #if FASTCDR_SIZEOF_LONG_DOUBLE == 16
672  current_position_.rmemcopy(ldouble_t, total_size);
673  current_position_ += total_size;
674 #else
675 #if FASTCDR_SIZEOF_LONG_DOUBLE == 8
676  for (size_t idx = 0; idx < num_elements; ++idx)
677  {
678  current_position_ += 8;
679  current_position_ >> ldouble_t[idx];
680  current_position_ += 8;
681  }
682 #else
683 #error unsupported long double type and no __float128 available
684 #endif // FASTCDR_SIZEOF_LONG_DOUBLE == 8
685 #endif // FASTCDR_SIZEOF_LONG_DOUBLE == 16
686 #endif // FASTCDR_HAVE_FLOAT128 && FASTCDR_SIZEOF_LONG_DOUBLE < 16
687 
688  return *this;
689  }
690 
692 }
693 
695  const std::vector<bool>& vector_t)
696 {
697  state state_before_error(*this);
698 
699  *this << static_cast<int32_t>(vector_t.size());
700 
701  size_t total_size = vector_t.size() * sizeof(bool);
702 
703  if (((last_position_ - current_position_) >= total_size) || resize(total_size))
704  {
705  for (size_t count = 0; count < vector_t.size(); ++count)
706  {
707  uint8_t value = 0;
708  std::vector<bool>::const_reference ref = vector_t[count];
709 
710  if (ref)
711  {
712  value = 1;
713  }
714  current_position_++ << value;
715  }
716  }
717  else
718  {
719  set_state(state_before_error);
721  }
722 
723  return *this;
724 }
725 
727  std::vector<bool>& vector_t)
728 {
729  uint32_t sequence_length = 0;
730  state state_before_error(*this);
731 
732  *this >> sequence_length;
733 
734  size_t total_size = sequence_length * sizeof(bool);
735 
736  if ((last_position_ - current_position_) >= total_size)
737  {
738  vector_t.resize(sequence_length);
739  for (uint32_t count = 0; count < sequence_length; ++count)
740  {
741  uint8_t value = 0;
742  current_position_++ >> value;
743 
744  if (value == 1)
745  {
746  vector_t[count] = true;
747  }
748  else if (value == 0)
749  {
750  vector_t[count] = false;
751  }
752  }
753  }
754  else
755  {
756  set_state(state_before_error);
758  }
759 
760  return *this;
761 }
762 
764  std::string*& sequence_t,
765  size_t& num_elements)
766 {
767  uint32_t sequence_length = 0;
768  state state_before_error(*this);
769 
770  deserialize(sequence_length);
771 
772  try
773  {
774  sequence_t = new std::string[sequence_length];
775  deserialize_array(sequence_t, sequence_length);
776  }
778  {
779  delete [] sequence_t;
780  sequence_t = NULL;
781  set_state(state_before_error);
782  ex.raise();
783  }
784 
785  num_elements = sequence_length;
786  return *this;
787 }
788 
790  std::wstring*& sequence_t,
791  size_t& num_elements)
792 {
793  uint32_t sequence_length = 0;
794  state state_before_error(*this);
795 
796  deserialize(sequence_length);
797 
798  try
799  {
800  sequence_t = new std::wstring[sequence_length];
801  deserialize_array(sequence_t, sequence_length);
802  }
804  {
805  delete [] sequence_t;
806  sequence_t = NULL;
807  set_state(state_before_error);
808  ex.raise();
809  }
810 
811  num_elements = sequence_length;
812  return *this;
813 }
BadParamException.h
eprosima::fastcdr::FastCdr::serialize
FastCdr & serialize(const uint8_t octet_t)
This function serializes an octet.
Definition: FastCdr.h:634
eprosima::fastcdr
Definition: fixed_size_string.hpp:33
eprosima::fastcdr::exception::BadParamException
This class is thrown as an exception when an invalid parameter is being serialized.
Definition: BadParamException.h:27
eprosima::fastcdr::_FastBuffer_iterator::memcopy
void memcopy(const void *src, const size_t size)
This function copies a buffer into the raw buffer.
Definition: FastBuffer.h:126
detail::state
state
Definition: core.h:2305
eprosima::fastcdr::FastCdr::current_position_
FastBuffer::iterator current_position_
The current position in the serialization/deserialization process.
Definition: FastCdr.h:2070
eprosima::fastcdr::FastCdr
This class offers an interface to serialize/deserialize some basic types using a modified CDR protoco...
Definition: FastCdr.h:40
eprosima::fastcdr::FastCdr::deserialize_wstring_sequence
FastCdr & deserialize_wstring_sequence(std::wstring *&sequence_t, size_t &num_elements)
Definition: FastCdr.cpp:789
eprosima::fastcdr::FastCdr::FastCdr
FastCdr(FastBuffer &cdr_buffer)
This constructor creates a eprosima::fastcdr::FastCdr object that can serialize/deserialize the assig...
Definition: FastCdr.cpp:34
eprosima::fastcdr::_FastBuffer_iterator::rmemcopy
void rmemcopy(void *dst, const size_t size)
This function copies from the raw buffer to a external buffer.
Definition: FastBuffer.h:142
eprosima::fastcdr::FastCdr::state
This class stores the current state of a CDR serialization.
Definition: FastCdr.h:47
eprosima::fastcdr::FastBuffer::begin
iterator begin()
This function returns a iterator that points to the begining of the stream.
Definition: FastBuffer.h:317
eprosima::fastcdr::FastCdr::deserialize_array
FastCdr & deserialize_array(uint8_t *octet_t, size_t num_elements)
This function deserializes an array of octets.
Definition: FastCdr.h:1656
eprosima::fastcdr::FastCdr::serialize_array
FastCdr & serialize_array(const uint8_t *octet_t, size_t num_elements)
This function serializes an array of octets.
Definition: FastCdr.h:998
eprosima::fastcdr::FastCdr::reset
void reset()
This function resets the current position in the buffer to the begining.
Definition: FastCdr.cpp:72
eprosima::fastcdr::FastCdr::resize
bool resize(size_t min_size_inc)
Definition: FastCdr.cpp:77
eprosima::fastcdr::FastBuffer::resize
bool resize(size_t min_size_inc)
This function resizes the raw buffer. It will call the user's defined function for this purpose.
Definition: FastBuffer.cpp:59
eprosima::fastcdr::FastCdr::deserialize
FastCdr & deserialize(uint8_t &octet_t)
This function deserializes an octet.
Definition: FastCdr.h:1276
size_to_uint32
uint32_t size_to_uint32(size_t val)
Definition: FastBuffer.h:25
eprosima::fastcdr::FastCdr::read_wstring
std::wstring read_wstring(uint32_t &length)
Definition: FastCdr.cpp:480
eprosima::fastcdr::FastCdr::read_string
const char * read_string(uint32_t &length)
Definition: FastCdr.cpp:452
eprosima::fastcdr::exception::Exception
This abstract class is used to create exceptions.
Definition: Exception.h:29
eprosima::fastcdr::FastCdr::state::current_position_
const FastBuffer::iterator current_position_
The position in the buffer when the state was created.
Definition: FastCdr.h:71
eprosima::fastcdr::FastCdr::set_state
void set_state(FastCdr::state &state)
This function sets a previous state of the CDR stream;.
Definition: FastCdr.cpp:66
eprosima::fastcdr::FastCdr::deserialize_bool_sequence
FastCdr & deserialize_bool_sequence(std::vector< bool > &vector_t)
Definition: FastCdr.cpp:726
eprosima::fastcdr::FastCdr::get_state
FastCdr::state get_state()
This function returns the current state of the CDR stream.
Definition: FastCdr.cpp:61
eprosima::fastcdr::exception::NotEnoughMemoryException
This class is thrown as an exception when the buffer's internal memory reachs its size limit.
Definition: NotEnoughMemoryException.h:27
eprosima::fastcdr::FastCdr::cdr_buffer_
FastBuffer & cdr_buffer_
Reference to the buffer that will be serialized/deserialized.
Definition: FastCdr.h:2067
eprosima::fastcdr::FastCdr::state::state
state(const FastCdr &fastcdr)
Default constructor.
Definition: FastCdr.cpp:22
eprosima::fastcdr::exception::Exception::raise
virtual Cdr_DllAPI void raise() const =0
This function throws the object as exception.
eprosima::fastcdr::FastCdr::serialize_bool_sequence
FastCdr & serialize_bool_sequence(const std::vector< bool > &vector_t)
Definition: FastCdr.cpp:694
eprosima::fastcdr::FastCdr::last_position_
FastBuffer::iterator last_position_
The last position in the buffer;.
Definition: FastCdr.h:2073
eprosima::fastcdr::FastBuffer
This class represents a stream of bytes that contains (or will contain) serialized data....
Definition: FastBuffer.h:243
eprosima::fastcdr::FastCdr::jump
bool jump(size_t num_bytes)
This function skips a number of bytes in the CDR stream buffer.
Definition: FastCdr.cpp:42
char_t
typename detail::char_t_impl< S >::type char_t
Definition: core.h:664
eprosima::fastcdr::FastBuffer::end
iterator end()
This function returns a iterator that points to the end of the stream.
Definition: FastBuffer.h:327
eprosima::fastcdr::FastCdr::get_current_position
char * get_current_position()
This function returns the current position in the CDR stream.
Definition: FastCdr.cpp:56
eprosima::fastcdr::exception::NotEnoughMemoryException::NOT_ENOUGH_MEMORY_MESSAGE_DEFAULT
static const Cdr_DllAPI char *const NOT_ENOUGH_MEMORY_MESSAGE_DEFAULT
Default message used in the library.
Definition: NotEnoughMemoryException.h:78
FastCdr.h
eprosima::fastcdr::FastCdr::deserialize_string_sequence
FastCdr & deserialize_string_sequence(std::string *&sequence_t, size_t &num_elements)
Definition: FastCdr.cpp:763


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:44