lib.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include <stdint.h>
  2. #include <stddef.h>
  3. #ifdef _OPENMP
  4. #include <omp.h>
  5. #endif
  6. #include "../include/libbase64.h"
  7. #include "tables/tables.h"
  8. #include "codecs.h"
  9. #include "env.h"
  10. // These static function pointers are initialized once when the library is
  11. // first used, and remain in use for the remaining lifetime of the program.
  12. // The idea being that CPU features don't change at runtime.
  13. static struct codec codec = { NULL, NULL };
  14. void
  15. base64_stream_encode_init (struct base64_state *state, int flags)
  16. {
  17. // If any of the codec flags are set, redo choice:
  18. if (codec.enc == NULL || flags & 0xFF) {
  19. codec_choose(&codec, flags);
  20. }
  21. state->eof = 0;
  22. state->bytes = 0;
  23. state->carry = 0;
  24. state->flags = flags;
  25. }
  26. void
  27. base64_stream_encode
  28. ( struct base64_state *state
  29. , const char *src
  30. , size_t srclen
  31. , char *out
  32. , size_t *outlen
  33. )
  34. {
  35. codec.enc(state, src, srclen, out, outlen);
  36. }
  37. void
  38. base64_stream_encode_final
  39. ( struct base64_state *state
  40. , char *out
  41. , size_t *outlen
  42. )
  43. {
  44. uint8_t *o = (uint8_t *)out;
  45. if (state->bytes == 1) {
  46. *o++ = base64_table_enc_6bit[state->carry];
  47. *o++ = '=';
  48. *o++ = '=';
  49. *outlen = 3;
  50. return;
  51. }
  52. if (state->bytes == 2) {
  53. *o++ = base64_table_enc_6bit[state->carry];
  54. *o++ = '=';
  55. *outlen = 2;
  56. return;
  57. }
  58. *outlen = 0;
  59. }
  60. void
  61. base64_stream_decode_init (struct base64_state *state, int flags)
  62. {
  63. // If any of the codec flags are set, redo choice:
  64. if (codec.dec == NULL || flags & 0xFFFF) {
  65. codec_choose(&codec, flags);
  66. }
  67. state->eof = 0;
  68. state->bytes = 0;
  69. state->carry = 0;
  70. state->flags = flags;
  71. }
  72. int
  73. base64_stream_decode
  74. ( struct base64_state *state
  75. , const char *src
  76. , size_t srclen
  77. , char *out
  78. , size_t *outlen
  79. )
  80. {
  81. return codec.dec(state, src, srclen, out, outlen);
  82. }
  83. #ifdef _OPENMP
  84. // Due to the overhead of initializing OpenMP and creating a team of
  85. // threads, we require the data length to be larger than a threshold:
  86. #define OMP_THRESHOLD 20000
  87. // Conditionally include OpenMP-accelerated codec implementations:
  88. #include "lib_openmp.c"
  89. #endif
  90. void
  91. base64_encode
  92. ( const char *src
  93. , size_t srclen
  94. , char *out
  95. , size_t *outlen
  96. , int flags
  97. )
  98. {
  99. size_t s;
  100. size_t t;
  101. struct base64_state state;
  102. #ifdef _OPENMP
  103. if (srclen >= OMP_THRESHOLD) {
  104. base64_encode_openmp(src, srclen, out, outlen, flags);
  105. return;
  106. }
  107. #endif
  108. // Init the stream reader:
  109. base64_stream_encode_init(&state, flags);
  110. // Feed the whole string to the stream reader:
  111. base64_stream_encode(&state, src, srclen, out, &s);
  112. // Finalize the stream by writing trailer if any:
  113. base64_stream_encode_final(&state, out + s, &t);
  114. // Final output length is stream length plus tail:
  115. *outlen = s + t;
  116. }
  117. int
  118. base64_decode
  119. ( const char *src
  120. , size_t srclen
  121. , char *out
  122. , size_t *outlen
  123. , int flags
  124. )
  125. {
  126. int ret;
  127. struct base64_state state;
  128. #ifdef _OPENMP
  129. if (srclen >= OMP_THRESHOLD) {
  130. return base64_decode_openmp(src, srclen, out, outlen, flags);
  131. }
  132. #endif
  133. // Init the stream reader:
  134. base64_stream_decode_init(&state, flags);
  135. // Feed the whole string to the stream reader:
  136. ret = base64_stream_decode(&state, src, srclen, out, outlen);
  137. // If when decoding a whole block, we're still waiting for input then fail:
  138. if (ret && (state.bytes == 0)) {
  139. return ret;
  140. }
  141. return 0;
  142. }