/src/boringssl/include/openssl/stack.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
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 | | // 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 | | #ifndef OPENSSL_HEADER_STACK_H |
16 | | #define OPENSSL_HEADER_STACK_H |
17 | | |
18 | | #include <openssl/base.h> // IWYU pragma: export |
19 | | |
20 | | #if defined(__cplusplus) |
21 | | extern "C" { |
22 | | #endif |
23 | | |
24 | | |
25 | | // A stack, in OpenSSL, is an array of pointers. They are the most commonly |
26 | | // used collection object. |
27 | | // |
28 | | // This file defines macros for type-safe use of the stack functions. A stack |
29 | | // type is named like |STACK_OF(FOO)| and is accessed with functions named |
30 | | // like |sk_FOO_*|. Note the stack will typically contain /pointers/ to |FOO|. |
31 | | // |
32 | | // The |DECLARE_STACK_OF| macro makes |STACK_OF(FOO)| available, and |
33 | | // |DEFINE_STACK_OF| makes the corresponding functions available. |
34 | | |
35 | | |
36 | | // Defining stacks. |
37 | | |
38 | | // STACK_OF expands to the stack type for |type|. |
39 | | #define STACK_OF(type) struct stack_st_##type |
40 | | |
41 | | // DECLARE_STACK_OF declares the |STACK_OF(type)| type. It does not make the |
42 | | // corresponding |sk_type_*| functions available. This macro should be used in |
43 | | // files which only need the type. |
44 | | #define DECLARE_STACK_OF(type) STACK_OF(type); |
45 | | |
46 | | // DEFINE_NAMED_STACK_OF defines |STACK_OF(name)| to be a stack whose elements |
47 | | // are |type| *. This macro makes the |sk_name_*| functions available. |
48 | | // |
49 | | // It is not necessary to use |DECLARE_STACK_OF| in files which use this macro. |
50 | | #define DEFINE_NAMED_STACK_OF(name, type) \ |
51 | | BORINGSSL_DEFINE_STACK_OF_IMPL(name, type *, const type *) \ |
52 | | BORINGSSL_DEFINE_STACK_TRAITS(name, type, false) |
53 | | |
54 | | // DEFINE_STACK_OF defines |STACK_OF(type)| to be a stack whose elements are |
55 | | // |type| *. This macro makes the |sk_type_*| functions available. |
56 | | // |
57 | | // It is not necessary to use |DECLARE_STACK_OF| in files which use this macro. |
58 | | #define DEFINE_STACK_OF(type) DEFINE_NAMED_STACK_OF(type, type) |
59 | | |
60 | | // DEFINE_CONST_STACK_OF defines |STACK_OF(type)| to be a stack whose elements |
61 | | // are const |type| *. This macro makes the |sk_type_*| functions available. |
62 | | // |
63 | | // It is not necessary to use |DECLARE_STACK_OF| in files which use this macro. |
64 | | #define DEFINE_CONST_STACK_OF(type) \ |
65 | | BORINGSSL_DEFINE_STACK_OF_IMPL(type, const type *, const type *) \ |
66 | | BORINGSSL_DEFINE_STACK_TRAITS(type, const type, true) |
67 | | |
68 | | |
69 | | // Using stacks. |
70 | | // |
71 | | // After the |DEFINE_STACK_OF| macro is used, the following functions are |
72 | | // available. |
73 | | |
74 | | #if 0 // Sample |
75 | | |
76 | | // sk_SAMPLE_free_func is a callback to free an element in a stack. |
77 | | typedef void (*sk_SAMPLE_free_func)(SAMPLE *); |
78 | | |
79 | | // sk_SAMPLE_copy_func is a callback to copy an element in a stack. It should |
80 | | // return the copy or NULL on error. |
81 | | typedef SAMPLE *(*sk_SAMPLE_copy_func)(const SAMPLE *); |
82 | | |
83 | | // sk_SAMPLE_cmp_func is a callback to compare |*a| to |*b|. It should return a |
84 | | // value < 0, 0, or > 0 if |*a| is less than, equal to, or greater than |*b|, |
85 | | // respectively. Note the extra indirection - the function is given a pointer |
86 | | // to a pointer to the element. This is the |qsort|/|bsearch| comparison |
87 | | // function applied to an array of |SAMPLE*|. |
88 | | typedef int (*sk_SAMPLE_cmp_func)(const SAMPLE *const *a, |
89 | | const SAMPLE *const *b); |
90 | | |
91 | | // sk_SAMPLE_new creates a new, empty stack with the given comparison function, |
92 | | // which may be NULL. It returns the new stack or NULL on allocation failure. |
93 | | STACK_OF(SAMPLE) *sk_SAMPLE_new(sk_SAMPLE_cmp_func comp); |
94 | | |
95 | | // sk_SAMPLE_new_null creates a new, empty stack. It returns the new stack or |
96 | | // NULL on allocation failure. |
97 | | STACK_OF(SAMPLE) *sk_SAMPLE_new_null(void); |
98 | | |
99 | | // sk_SAMPLE_num returns the number of elements in |sk|. It is safe to cast this |
100 | | // value to |int|. |sk| is guaranteed to have at most |INT_MAX| elements. If |
101 | | // |sk| is NULL, it is treated as the empty list and this function returns zero. |
102 | | size_t sk_SAMPLE_num(const STACK_OF(SAMPLE) *sk); |
103 | | |
104 | | // sk_SAMPLE_zero resets |sk| to the empty state but does nothing to free the |
105 | | // individual elements themselves. |
106 | | void sk_SAMPLE_zero(STACK_OF(SAMPLE) *sk); |
107 | | |
108 | | // sk_SAMPLE_value returns the |i|th pointer in |sk|, or NULL if |i| is out of |
109 | | // range. If |sk| is NULL, it is treated as an empty list and the function |
110 | | // returns NULL. |
111 | | SAMPLE *sk_SAMPLE_value(const STACK_OF(SAMPLE) *sk, size_t i); |
112 | | |
113 | | // sk_SAMPLE_set sets the |i|th pointer in |sk| to |p| and returns |p|. If |i| |
114 | | // is out of range, it returns NULL. |
115 | | SAMPLE *sk_SAMPLE_set(STACK_OF(SAMPLE) *sk, size_t i, SAMPLE *p); |
116 | | |
117 | | // sk_SAMPLE_free frees |sk|, but does nothing to free the individual elements. |
118 | | // Use |sk_SAMPLE_pop_free| to also free the elements. |
119 | | void sk_SAMPLE_free(STACK_OF(SAMPLE) *sk); |
120 | | |
121 | | // sk_SAMPLE_pop_free calls |free_func| on each element in |sk| and then |
122 | | // frees the stack itself. |
123 | | void sk_SAMPLE_pop_free(STACK_OF(SAMPLE) *sk, sk_SAMPLE_free_func free_func); |
124 | | |
125 | | // sk_SAMPLE_insert inserts |p| into the stack at index |where|, moving existing |
126 | | // elements if needed. It returns the length of the new stack, or zero on |
127 | | // error. |
128 | | size_t sk_SAMPLE_insert(STACK_OF(SAMPLE) *sk, SAMPLE *p, size_t where); |
129 | | |
130 | | // sk_SAMPLE_delete removes the pointer at index |where|, moving other elements |
131 | | // down if needed. It returns the removed pointer, or NULL if |where| is out of |
132 | | // range. |
133 | | SAMPLE *sk_SAMPLE_delete(STACK_OF(SAMPLE) *sk, size_t where); |
134 | | |
135 | | // sk_SAMPLE_delete_ptr removes, at most, one instance of |p| from |sk| based on |
136 | | // pointer equality. If an instance of |p| is found then |p| is returned, |
137 | | // otherwise it returns NULL. |
138 | | SAMPLE *sk_SAMPLE_delete_ptr(STACK_OF(SAMPLE) *sk, const SAMPLE *p); |
139 | | |
140 | | // sk_SAMPLE_delete_if_func is the callback function for |sk_SAMPLE_delete_if|. |
141 | | // It should return one to remove |p| and zero to keep it. |
142 | | typedef int (*sk_SAMPLE_delete_if_func)(SAMPLE *p, void *data); |
143 | | |
144 | | // sk_SAMPLE_delete_if calls |func| with each element of |sk| and removes the |
145 | | // entries where |func| returned one. This function does not free or return |
146 | | // removed pointers so, if |sk| owns its contents, |func| should release the |
147 | | // pointers prior to returning one. |
148 | | void sk_SAMPLE_delete_if(STACK_OF(SAMPLE) *sk, sk_SAMPLE_delete_if_func func, |
149 | | void *data); |
150 | | |
151 | | // sk_SAMPLE_find find the first value in |sk| equal to |p|. |sk|'s comparison |
152 | | // function determines equality, or pointer equality if |sk| has no comparison |
153 | | // function. |
154 | | // |
155 | | // If the stack is sorted (see |sk_SAMPLE_sort|), this function uses a binary |
156 | | // search. Otherwise it performs a linear search. If it finds a matching |
157 | | // element, it writes the index to |*out_index| (if |out_index| is not NULL) and |
158 | | // returns one. Otherwise, it returns zero. If |sk| is NULL, it is treated as |
159 | | // the empty list and the function returns zero. |
160 | | // |
161 | | // Note this differs from OpenSSL. The type signature is slightly different, and |
162 | | // OpenSSL's version will implicitly sort |sk| if it has a comparison function |
163 | | // defined. |
164 | | int sk_SAMPLE_find(const STACK_OF(SAMPLE) *sk, size_t *out_index, |
165 | | const SAMPLE *p); |
166 | | |
167 | | // sk_SAMPLE_shift removes and returns the first element in |sk|, or NULL if |
168 | | // |sk| is empty. |
169 | | SAMPLE *sk_SAMPLE_shift(STACK_OF(SAMPLE) *sk); |
170 | | |
171 | | // sk_SAMPLE_push appends |p| to |sk| and returns the length of the new stack, |
172 | | // or 0 on allocation failure. |
173 | | size_t sk_SAMPLE_push(STACK_OF(SAMPLE) *sk, SAMPLE *p); |
174 | | |
175 | | // sk_SAMPLE_pop removes and returns the last element of |sk|, or NULL if |sk| |
176 | | // is empty. |
177 | | SAMPLE *sk_SAMPLE_pop(STACK_OF(SAMPLE) *sk); |
178 | | |
179 | | // sk_SAMPLE_dup performs a shallow copy of a stack and returns the new stack, |
180 | | // or NULL on error. Use |sk_SAMPLE_deep_copy| to also copy the elements. |
181 | | STACK_OF(SAMPLE) *sk_SAMPLE_dup(const STACK_OF(SAMPLE) *sk); |
182 | | |
183 | | // sk_SAMPLE_sort sorts the elements of |sk| into ascending order based on the |
184 | | // comparison function. The stack maintains a "sorted" flag and sorting an |
185 | | // already sorted stack is a no-op. |
186 | | void sk_SAMPLE_sort(STACK_OF(SAMPLE) *sk); |
187 | | |
188 | | // sk_SAMPLE_is_sorted returns one if |sk| is known to be sorted and zero |
189 | | // otherwise. |
190 | | int sk_SAMPLE_is_sorted(const STACK_OF(SAMPLE) *sk); |
191 | | |
192 | | // sk_SAMPLE_set_cmp_func sets the comparison function to be used by |sk| and |
193 | | // returns the previous one. |
194 | | sk_SAMPLE_cmp_func sk_SAMPLE_set_cmp_func(STACK_OF(SAMPLE) *sk, |
195 | | sk_SAMPLE_cmp_func comp); |
196 | | |
197 | | // sk_SAMPLE_deep_copy performs a copy of |sk| and of each of the non-NULL |
198 | | // elements in |sk| by using |copy_func|. If an error occurs, it calls |
199 | | // |free_func| to free any copies already made and returns NULL. |
200 | | STACK_OF(SAMPLE) *sk_SAMPLE_deep_copy(const STACK_OF(SAMPLE) *sk, |
201 | | sk_SAMPLE_copy_func copy_func, |
202 | | sk_SAMPLE_free_func free_func); |
203 | | |
204 | | #endif // Sample |
205 | | |
206 | | |
207 | | // Private functions. |
208 | | // |
209 | | // The |sk_*| functions generated above are implemented internally using the |
210 | | // type-erased functions below. Callers should use the typed wrappers instead. |
211 | | // When using the type-erased functions, callers are responsible for ensuring |
212 | | // the underlying types are correct. Casting pointers to the wrong types will |
213 | | // result in memory errors. |
214 | | |
215 | | // OPENSSL_sk_free_func is a function that frees an element in a stack. Note its |
216 | | // actual type is void (*)(T *) for some T. Low-level |sk_*| functions will be |
217 | | // passed a type-specific wrapper to call it correctly. |
218 | | typedef void (*OPENSSL_sk_free_func)(void *ptr); |
219 | | |
220 | | // OPENSSL_sk_copy_func is a function that copies an element in a stack. Note |
221 | | // its actual type is T *(*)(const T *) for some T. Low-level |sk_*| functions |
222 | | // will be passed a type-specific wrapper to call it correctly. |
223 | | typedef void *(*OPENSSL_sk_copy_func)(const void *ptr); |
224 | | |
225 | | // OPENSSL_sk_cmp_func is a comparison function that returns a value < 0, 0 or > |
226 | | // 0 if |*a| is less than, equal to or greater than |*b|, respectively. Note |
227 | | // the extra indirection - the function is given a pointer to a pointer to the |
228 | | // element. This differs from the usual qsort/bsearch comparison function. |
229 | | // |
230 | | // Note its actual type is |int (*)(const T *const *a, const T *const *b)|. |
231 | | // Low-level |sk_*| functions will be passed a type-specific wrapper to call it |
232 | | // correctly. |
233 | | typedef int (*OPENSSL_sk_cmp_func)(const void *const *a, const void *const *b); |
234 | | |
235 | | // OPENSSL_sk_delete_if_func is the generic version of |
236 | | // |sk_SAMPLE_delete_if_func|. |
237 | | typedef int (*OPENSSL_sk_delete_if_func)(void *obj, void *data); |
238 | | |
239 | | // The following function types call the above type-erased signatures with the |
240 | | // true types. |
241 | | typedef void (*OPENSSL_sk_call_free_func)(OPENSSL_sk_free_func, void *); |
242 | | typedef void *(*OPENSSL_sk_call_copy_func)(OPENSSL_sk_copy_func, const void *); |
243 | | typedef int (*OPENSSL_sk_call_cmp_func)(OPENSSL_sk_cmp_func, const void *, |
244 | | const void *); |
245 | | typedef int (*OPENSSL_sk_call_delete_if_func)(OPENSSL_sk_delete_if_func, void *, |
246 | | void *); |
247 | | |
248 | | // An OPENSSL_STACK contains an array of pointers. It is not designed to be used |
249 | | // directly, rather the wrapper macros should be used. |
250 | | typedef struct stack_st OPENSSL_STACK; |
251 | | |
252 | | // The following are raw stack functions. They implement the corresponding typed |
253 | | // |sk_SAMPLE_*| functions generated by |DEFINE_STACK_OF|. Callers shouldn't be |
254 | | // using them. Rather, callers should use the typed functions. |
255 | | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_cmp_func comp); |
256 | | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_new_null(void); |
257 | | OPENSSL_EXPORT size_t OPENSSL_sk_num(const OPENSSL_STACK *sk); |
258 | | OPENSSL_EXPORT void OPENSSL_sk_zero(OPENSSL_STACK *sk); |
259 | | OPENSSL_EXPORT void *OPENSSL_sk_value(const OPENSSL_STACK *sk, size_t i); |
260 | | OPENSSL_EXPORT void *OPENSSL_sk_set(OPENSSL_STACK *sk, size_t i, void *p); |
261 | | OPENSSL_EXPORT void OPENSSL_sk_free(OPENSSL_STACK *sk); |
262 | | OPENSSL_EXPORT void OPENSSL_sk_pop_free_ex( |
263 | | OPENSSL_STACK *sk, OPENSSL_sk_call_free_func call_free_func, |
264 | | OPENSSL_sk_free_func free_func); |
265 | | OPENSSL_EXPORT size_t OPENSSL_sk_insert(OPENSSL_STACK *sk, void *p, |
266 | | size_t where); |
267 | | OPENSSL_EXPORT void *OPENSSL_sk_delete(OPENSSL_STACK *sk, size_t where); |
268 | | OPENSSL_EXPORT void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *sk, const void *p); |
269 | | OPENSSL_EXPORT void OPENSSL_sk_delete_if( |
270 | | OPENSSL_STACK *sk, OPENSSL_sk_call_delete_if_func call_func, |
271 | | OPENSSL_sk_delete_if_func func, void *data); |
272 | | OPENSSL_EXPORT int OPENSSL_sk_find(const OPENSSL_STACK *sk, size_t *out_index, |
273 | | const void *p, |
274 | | OPENSSL_sk_call_cmp_func call_cmp_func); |
275 | | OPENSSL_EXPORT void *OPENSSL_sk_shift(OPENSSL_STACK *sk); |
276 | | OPENSSL_EXPORT size_t OPENSSL_sk_push(OPENSSL_STACK *sk, void *p); |
277 | | OPENSSL_EXPORT void *OPENSSL_sk_pop(OPENSSL_STACK *sk); |
278 | | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk); |
279 | | OPENSSL_EXPORT void OPENSSL_sk_sort(OPENSSL_STACK *sk, |
280 | | OPENSSL_sk_call_cmp_func call_cmp_func); |
281 | | OPENSSL_EXPORT int OPENSSL_sk_is_sorted(const OPENSSL_STACK *sk); |
282 | | OPENSSL_EXPORT OPENSSL_sk_cmp_func |
283 | | OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk, OPENSSL_sk_cmp_func comp); |
284 | | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_deep_copy( |
285 | | const OPENSSL_STACK *sk, OPENSSL_sk_call_copy_func call_copy_func, |
286 | | OPENSSL_sk_copy_func copy_func, OPENSSL_sk_call_free_func call_free_func, |
287 | | OPENSSL_sk_free_func free_func); |
288 | | |
289 | | |
290 | | // Deprecated private functions (hidden). |
291 | | // |
292 | | // TODO(crbug.com/boringssl/499): Migrate callers to the typed wrappers, or at |
293 | | // least the new names and remove the old ones. |
294 | | // |
295 | | // TODO(b/290792019, b/290785937): Ideally these would at least be inline |
296 | | // functions, so we do not squat the symbols. |
297 | | |
298 | | typedef OPENSSL_STACK _STACK; |
299 | | |
300 | | // The following functions call the corresponding |OPENSSL_sk_*| function. |
301 | | OPENSSL_EXPORT OPENSSL_DEPRECATED OPENSSL_STACK *sk_new_null(void); |
302 | | OPENSSL_EXPORT OPENSSL_DEPRECATED size_t sk_num(const OPENSSL_STACK *sk); |
303 | | OPENSSL_EXPORT OPENSSL_DEPRECATED void *sk_value(const OPENSSL_STACK *sk, |
304 | | size_t i); |
305 | | OPENSSL_EXPORT OPENSSL_DEPRECATED void sk_free(OPENSSL_STACK *sk); |
306 | | OPENSSL_EXPORT OPENSSL_DEPRECATED size_t sk_push(OPENSSL_STACK *sk, void *p); |
307 | | OPENSSL_EXPORT OPENSSL_DEPRECATED void *sk_pop(OPENSSL_STACK *sk); |
308 | | |
309 | | // sk_pop_free_ex calls |OPENSSL_sk_pop_free_ex|. |
310 | | // |
311 | | // TODO(b/291994116): Remove this. |
312 | | OPENSSL_EXPORT OPENSSL_DEPRECATED void sk_pop_free_ex( |
313 | | OPENSSL_STACK *sk, OPENSSL_sk_call_free_func call_free_func, |
314 | | OPENSSL_sk_free_func free_func); |
315 | | |
316 | | // sk_pop_free behaves like |OPENSSL_sk_pop_free_ex| but performs an invalid |
317 | | // function pointer cast. It exists because some existing callers called |
318 | | // |sk_pop_free| directly. |
319 | | // |
320 | | // TODO(davidben): Migrate callers to bssl::UniquePtr and remove this. |
321 | | OPENSSL_EXPORT OPENSSL_DEPRECATED void sk_pop_free( |
322 | | OPENSSL_STACK *sk, OPENSSL_sk_free_func free_func); |
323 | | |
324 | | |
325 | | #if !defined(BORINGSSL_NO_CXX) |
326 | | extern "C++" { |
327 | | BSSL_NAMESPACE_BEGIN |
328 | | namespace internal { |
329 | | template <typename T> |
330 | | struct StackTraits {}; |
331 | | } |
332 | | BSSL_NAMESPACE_END |
333 | | } |
334 | | |
335 | | #define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) \ |
336 | | extern "C++" { \ |
337 | | BSSL_NAMESPACE_BEGIN \ |
338 | | namespace internal { \ |
339 | | template <> \ |
340 | | struct StackTraits<STACK_OF(name)> { \ |
341 | | static constexpr bool kIsStack = true; \ |
342 | | using Type = type; \ |
343 | | static constexpr bool kIsConst = is_const; \ |
344 | | }; \ |
345 | | } \ |
346 | | BSSL_NAMESPACE_END \ |
347 | | } |
348 | | |
349 | | #else |
350 | | #define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) |
351 | | #endif |
352 | | |
353 | | #define BORINGSSL_DEFINE_STACK_OF_IMPL(name, ptrtype, constptrtype) \ |
354 | | /* We disable MSVC C4191 in this macro, which warns when pointers are cast \ |
355 | | * to the wrong type. While the cast itself is valid, it is often a bug \ |
356 | | * because calling it through the cast is UB. However, we never actually \ |
357 | | * call functions as |OPENSSL_sk_cmp_func|. The type is just a type-erased \ |
358 | | * function pointer. (C does not guarantee function pointers fit in \ |
359 | | * |void*|, and GCC will warn on this.) Thus we just disable the false \ |
360 | | * positive warning. */ \ |
361 | | OPENSSL_MSVC_PRAGMA(warning(push)) \ |
362 | | OPENSSL_MSVC_PRAGMA(warning(disable : 4191)) \ |
363 | | OPENSSL_GNUC_CLANG_PRAGMA("GCC diagnostic push") \ |
364 | | OPENSSL_CLANG_PRAGMA( \ |
365 | | "clang diagnostic ignored \"-Wunknown-warning-option\"") \ |
366 | | OPENSSL_CLANG_PRAGMA( \ |
367 | | "clang diagnostic ignored \"-Wcast-function-type-strict\"") \ |
368 | | /* We also disable -Wcast-qual. As part of this C-based type erasure setup, \ |
369 | | * the wrapper macros need to cast away const in places. In C++, const_cast \ |
370 | | * suppresses the warning, but it seemingly cannot be suppressed in C. */ \ |
371 | | OPENSSL_GNUC_CLANG_PRAGMA("GCC diagnostic ignored \"-Wcast-qual\"") \ |
372 | | \ |
373 | | DECLARE_STACK_OF(name) \ |
374 | | \ |
375 | | typedef void (*sk_##name##_free_func)(ptrtype); \ |
376 | | typedef ptrtype (*sk_##name##_copy_func)(constptrtype); \ |
377 | | typedef int (*sk_##name##_cmp_func)(constptrtype const *, \ |
378 | | constptrtype const *); \ |
379 | | typedef int (*sk_##name##_delete_if_func)(ptrtype, void *); \ |
380 | | \ |
381 | | OPENSSL_INLINE void sk_##name##_call_free_func( \ |
382 | 0 | OPENSSL_sk_free_func free_func, void *ptr) { \ |
383 | 0 | ((sk_##name##_free_func)free_func)((ptrtype)ptr); \ |
384 | 0 | } \ Unexecuted instantiation: sk_void_call_free_func Unexecuted instantiation: sk_OPENSSL_STRING_call_free_func Unexecuted instantiation: sk_BIO_call_free_func Unexecuted instantiation: sk_ASN1_INTEGER_call_free_func Unexecuted instantiation: sk_ASN1_OBJECT_call_free_func Unexecuted instantiation: sk_ASN1_TYPE_call_free_func Unexecuted instantiation: sk_ASN1_VALUE_call_free_func |
385 | | \ |
386 | | OPENSSL_INLINE void *sk_##name##_call_copy_func( \ |
387 | 0 | OPENSSL_sk_copy_func copy_func, const void *ptr) { \ |
388 | 0 | return (void *)((sk_##name##_copy_func)copy_func)((constptrtype)ptr); \ |
389 | 0 | } \ Unexecuted instantiation: sk_void_call_copy_func Unexecuted instantiation: sk_OPENSSL_STRING_call_copy_func Unexecuted instantiation: sk_BIO_call_copy_func Unexecuted instantiation: sk_ASN1_INTEGER_call_copy_func Unexecuted instantiation: sk_ASN1_OBJECT_call_copy_func Unexecuted instantiation: sk_ASN1_TYPE_call_copy_func Unexecuted instantiation: sk_ASN1_VALUE_call_copy_func |
390 | | \ |
391 | | OPENSSL_INLINE int sk_##name##_call_cmp_func(OPENSSL_sk_cmp_func cmp_func, \ |
392 | 0 | const void *a, const void *b) { \ |
393 | 0 | constptrtype a_ptr = (constptrtype)a; \ |
394 | 0 | constptrtype b_ptr = (constptrtype)b; \ |
395 | 0 | /* |cmp_func| expects an extra layer of pointers to match qsort. */ \ |
396 | 0 | return ((sk_##name##_cmp_func)cmp_func)(&a_ptr, &b_ptr); \ |
397 | 0 | } \ Unexecuted instantiation: sk_void_call_cmp_func Unexecuted instantiation: sk_OPENSSL_STRING_call_cmp_func Unexecuted instantiation: sk_BIO_call_cmp_func Unexecuted instantiation: sk_ASN1_INTEGER_call_cmp_func Unexecuted instantiation: sk_ASN1_OBJECT_call_cmp_func Unexecuted instantiation: sk_ASN1_TYPE_call_cmp_func Unexecuted instantiation: sk_ASN1_VALUE_call_cmp_func |
398 | | \ |
399 | | OPENSSL_INLINE int sk_##name##_call_delete_if_func( \ |
400 | 0 | OPENSSL_sk_delete_if_func func, void *obj, void *data) { \ |
401 | 0 | return ((sk_##name##_delete_if_func)func)((ptrtype)obj, data); \ |
402 | 0 | } \ Unexecuted instantiation: sk_void_call_delete_if_func Unexecuted instantiation: sk_OPENSSL_STRING_call_delete_if_func Unexecuted instantiation: sk_BIO_call_delete_if_func Unexecuted instantiation: sk_ASN1_INTEGER_call_delete_if_func Unexecuted instantiation: sk_ASN1_OBJECT_call_delete_if_func Unexecuted instantiation: sk_ASN1_TYPE_call_delete_if_func Unexecuted instantiation: sk_ASN1_VALUE_call_delete_if_func |
403 | | \ |
404 | 0 | OPENSSL_INLINE STACK_OF(name) *sk_##name##_new(sk_##name##_cmp_func comp) { \ |
405 | 0 | return (STACK_OF(name) *)OPENSSL_sk_new((OPENSSL_sk_cmp_func)comp); \ |
406 | 0 | } \ Unexecuted instantiation: sk_void_new Unexecuted instantiation: sk_OPENSSL_STRING_new Unexecuted instantiation: sk_BIO_new Unexecuted instantiation: sk_ASN1_INTEGER_new Unexecuted instantiation: sk_ASN1_OBJECT_new Unexecuted instantiation: sk_ASN1_TYPE_new Unexecuted instantiation: sk_ASN1_VALUE_new |
407 | | \ |
408 | 0 | OPENSSL_INLINE STACK_OF(name) *sk_##name##_new_null(void) { \ |
409 | 0 | return (STACK_OF(name) *)OPENSSL_sk_new_null(); \ |
410 | 0 | } \ Unexecuted instantiation: sk_void_new_null Unexecuted instantiation: sk_OPENSSL_STRING_new_null Unexecuted instantiation: sk_BIO_new_null Unexecuted instantiation: sk_ASN1_INTEGER_new_null Unexecuted instantiation: sk_ASN1_OBJECT_new_null Unexecuted instantiation: sk_ASN1_TYPE_new_null Unexecuted instantiation: sk_ASN1_VALUE_new_null |
411 | | \ |
412 | 0 | OPENSSL_INLINE size_t sk_##name##_num(const STACK_OF(name) *sk) { \ |
413 | 0 | return OPENSSL_sk_num((const OPENSSL_STACK *)sk); \ |
414 | 0 | } \ Unexecuted instantiation: sk_void_num Unexecuted instantiation: sk_OPENSSL_STRING_num Unexecuted instantiation: sk_BIO_num Unexecuted instantiation: sk_ASN1_INTEGER_num Unexecuted instantiation: sk_ASN1_OBJECT_num Unexecuted instantiation: sk_ASN1_TYPE_num Unexecuted instantiation: sk_ASN1_VALUE_num |
415 | | \ |
416 | 0 | OPENSSL_INLINE void sk_##name##_zero(STACK_OF(name) *sk) { \ |
417 | 0 | OPENSSL_sk_zero((OPENSSL_STACK *)sk); \ |
418 | 0 | } \ Unexecuted instantiation: sk_void_zero Unexecuted instantiation: sk_OPENSSL_STRING_zero Unexecuted instantiation: sk_BIO_zero Unexecuted instantiation: sk_ASN1_INTEGER_zero Unexecuted instantiation: sk_ASN1_OBJECT_zero Unexecuted instantiation: sk_ASN1_TYPE_zero Unexecuted instantiation: sk_ASN1_VALUE_zero |
419 | | \ |
420 | | OPENSSL_INLINE ptrtype sk_##name##_value(const STACK_OF(name) *sk, \ |
421 | 0 | size_t i) { \ |
422 | 0 | return (ptrtype)OPENSSL_sk_value((const OPENSSL_STACK *)sk, i); \ |
423 | 0 | } \ Unexecuted instantiation: sk_void_value Unexecuted instantiation: sk_OPENSSL_STRING_value Unexecuted instantiation: sk_BIO_value Unexecuted instantiation: sk_ASN1_INTEGER_value Unexecuted instantiation: sk_ASN1_OBJECT_value Unexecuted instantiation: sk_ASN1_TYPE_value Unexecuted instantiation: sk_ASN1_VALUE_value |
424 | | \ |
425 | | OPENSSL_INLINE ptrtype sk_##name##_set(STACK_OF(name) *sk, size_t i, \ |
426 | 0 | ptrtype p) { \ |
427 | 0 | return (ptrtype)OPENSSL_sk_set((OPENSSL_STACK *)sk, i, (void *)p); \ |
428 | 0 | } \ Unexecuted instantiation: sk_void_set Unexecuted instantiation: sk_OPENSSL_STRING_set Unexecuted instantiation: sk_BIO_set Unexecuted instantiation: sk_ASN1_INTEGER_set Unexecuted instantiation: sk_ASN1_OBJECT_set Unexecuted instantiation: sk_ASN1_TYPE_set Unexecuted instantiation: sk_ASN1_VALUE_set |
429 | | \ |
430 | 0 | OPENSSL_INLINE void sk_##name##_free(STACK_OF(name) *sk) { \ |
431 | 0 | OPENSSL_sk_free((OPENSSL_STACK *)sk); \ |
432 | 0 | } \ Unexecuted instantiation: sk_void_free Unexecuted instantiation: sk_OPENSSL_STRING_free Unexecuted instantiation: sk_BIO_free Unexecuted instantiation: sk_ASN1_INTEGER_free Unexecuted instantiation: sk_ASN1_OBJECT_free Unexecuted instantiation: sk_ASN1_TYPE_free Unexecuted instantiation: sk_ASN1_VALUE_free |
433 | | \ |
434 | | OPENSSL_INLINE void sk_##name##_pop_free(STACK_OF(name) *sk, \ |
435 | 0 | sk_##name##_free_func free_func) { \ |
436 | 0 | OPENSSL_sk_pop_free_ex((OPENSSL_STACK *)sk, sk_##name##_call_free_func, \ |
437 | 0 | (OPENSSL_sk_free_func)free_func); \ |
438 | 0 | } \ Unexecuted instantiation: sk_void_pop_free Unexecuted instantiation: sk_OPENSSL_STRING_pop_free Unexecuted instantiation: sk_BIO_pop_free Unexecuted instantiation: sk_ASN1_INTEGER_pop_free Unexecuted instantiation: sk_ASN1_OBJECT_pop_free Unexecuted instantiation: sk_ASN1_TYPE_pop_free Unexecuted instantiation: sk_ASN1_VALUE_pop_free |
439 | | \ |
440 | | OPENSSL_INLINE size_t sk_##name##_insert(STACK_OF(name) *sk, ptrtype p, \ |
441 | 0 | size_t where) { \ |
442 | 0 | return OPENSSL_sk_insert((OPENSSL_STACK *)sk, (void *)p, where); \ |
443 | 0 | } \ Unexecuted instantiation: sk_void_insert Unexecuted instantiation: sk_OPENSSL_STRING_insert Unexecuted instantiation: sk_BIO_insert Unexecuted instantiation: sk_ASN1_INTEGER_insert Unexecuted instantiation: sk_ASN1_OBJECT_insert Unexecuted instantiation: sk_ASN1_TYPE_insert Unexecuted instantiation: sk_ASN1_VALUE_insert |
444 | | \ |
445 | | OPENSSL_INLINE ptrtype sk_##name##_delete(STACK_OF(name) *sk, \ |
446 | 0 | size_t where) { \ |
447 | 0 | return (ptrtype)OPENSSL_sk_delete((OPENSSL_STACK *)sk, where); \ |
448 | 0 | } \ Unexecuted instantiation: sk_void_delete Unexecuted instantiation: sk_OPENSSL_STRING_delete Unexecuted instantiation: sk_BIO_delete Unexecuted instantiation: sk_ASN1_INTEGER_delete Unexecuted instantiation: sk_ASN1_OBJECT_delete Unexecuted instantiation: sk_ASN1_TYPE_delete Unexecuted instantiation: sk_ASN1_VALUE_delete |
449 | | \ |
450 | | OPENSSL_INLINE ptrtype sk_##name##_delete_ptr(STACK_OF(name) *sk, \ |
451 | 0 | constptrtype p) { \ |
452 | 0 | return (ptrtype)OPENSSL_sk_delete_ptr((OPENSSL_STACK *)sk, \ |
453 | 0 | (const void *)p); \ |
454 | 0 | } \ Unexecuted instantiation: sk_void_delete_ptr Unexecuted instantiation: sk_OPENSSL_STRING_delete_ptr Unexecuted instantiation: sk_BIO_delete_ptr Unexecuted instantiation: sk_ASN1_INTEGER_delete_ptr Unexecuted instantiation: sk_ASN1_OBJECT_delete_ptr Unexecuted instantiation: sk_ASN1_TYPE_delete_ptr Unexecuted instantiation: sk_ASN1_VALUE_delete_ptr |
455 | | \ |
456 | | OPENSSL_INLINE void sk_##name##_delete_if( \ |
457 | 0 | STACK_OF(name) *sk, sk_##name##_delete_if_func func, void *data) { \ |
458 | 0 | OPENSSL_sk_delete_if((OPENSSL_STACK *)sk, sk_##name##_call_delete_if_func, \ |
459 | 0 | (OPENSSL_sk_delete_if_func)func, data); \ |
460 | 0 | } \ Unexecuted instantiation: sk_void_delete_if Unexecuted instantiation: sk_OPENSSL_STRING_delete_if Unexecuted instantiation: sk_BIO_delete_if Unexecuted instantiation: sk_ASN1_INTEGER_delete_if Unexecuted instantiation: sk_ASN1_OBJECT_delete_if Unexecuted instantiation: sk_ASN1_TYPE_delete_if Unexecuted instantiation: sk_ASN1_VALUE_delete_if |
461 | | \ |
462 | | OPENSSL_INLINE int sk_##name##_find(const STACK_OF(name) *sk, \ |
463 | 0 | size_t *out_index, constptrtype p) { \ |
464 | 0 | return OPENSSL_sk_find((const OPENSSL_STACK *)sk, out_index, \ |
465 | 0 | (const void *)p, sk_##name##_call_cmp_func); \ |
466 | 0 | } \ Unexecuted instantiation: sk_void_find Unexecuted instantiation: sk_OPENSSL_STRING_find Unexecuted instantiation: sk_BIO_find Unexecuted instantiation: sk_ASN1_INTEGER_find Unexecuted instantiation: sk_ASN1_OBJECT_find Unexecuted instantiation: sk_ASN1_TYPE_find Unexecuted instantiation: sk_ASN1_VALUE_find |
467 | | \ |
468 | 0 | OPENSSL_INLINE ptrtype sk_##name##_shift(STACK_OF(name) *sk) { \ |
469 | 0 | return (ptrtype)OPENSSL_sk_shift((OPENSSL_STACK *)sk); \ |
470 | 0 | } \ Unexecuted instantiation: sk_void_shift Unexecuted instantiation: sk_OPENSSL_STRING_shift Unexecuted instantiation: sk_BIO_shift Unexecuted instantiation: sk_ASN1_INTEGER_shift Unexecuted instantiation: sk_ASN1_OBJECT_shift Unexecuted instantiation: sk_ASN1_TYPE_shift Unexecuted instantiation: sk_ASN1_VALUE_shift |
471 | | \ |
472 | 0 | OPENSSL_INLINE size_t sk_##name##_push(STACK_OF(name) *sk, ptrtype p) { \ |
473 | 0 | return OPENSSL_sk_push((OPENSSL_STACK *)sk, (void *)p); \ |
474 | 0 | } \ Unexecuted instantiation: sk_void_push Unexecuted instantiation: sk_OPENSSL_STRING_push Unexecuted instantiation: sk_BIO_push Unexecuted instantiation: sk_ASN1_INTEGER_push Unexecuted instantiation: sk_ASN1_OBJECT_push Unexecuted instantiation: sk_ASN1_TYPE_push Unexecuted instantiation: sk_ASN1_VALUE_push |
475 | | \ |
476 | 0 | OPENSSL_INLINE ptrtype sk_##name##_pop(STACK_OF(name) *sk) { \ |
477 | 0 | return (ptrtype)OPENSSL_sk_pop((OPENSSL_STACK *)sk); \ |
478 | 0 | } \ Unexecuted instantiation: sk_void_pop Unexecuted instantiation: sk_OPENSSL_STRING_pop Unexecuted instantiation: sk_BIO_pop Unexecuted instantiation: sk_ASN1_INTEGER_pop Unexecuted instantiation: sk_ASN1_OBJECT_pop Unexecuted instantiation: sk_ASN1_TYPE_pop Unexecuted instantiation: sk_ASN1_VALUE_pop |
479 | | \ |
480 | 0 | OPENSSL_INLINE STACK_OF(name) *sk_##name##_dup(const STACK_OF(name) *sk) { \ |
481 | 0 | return (STACK_OF(name) *)OPENSSL_sk_dup((const OPENSSL_STACK *)sk); \ |
482 | 0 | } \ Unexecuted instantiation: sk_void_dup Unexecuted instantiation: sk_OPENSSL_STRING_dup Unexecuted instantiation: sk_BIO_dup Unexecuted instantiation: sk_ASN1_INTEGER_dup Unexecuted instantiation: sk_ASN1_OBJECT_dup Unexecuted instantiation: sk_ASN1_TYPE_dup Unexecuted instantiation: sk_ASN1_VALUE_dup |
483 | | \ |
484 | 0 | OPENSSL_INLINE void sk_##name##_sort(STACK_OF(name) *sk) { \ |
485 | 0 | OPENSSL_sk_sort((OPENSSL_STACK *)sk, sk_##name##_call_cmp_func); \ |
486 | 0 | } \ Unexecuted instantiation: sk_void_sort Unexecuted instantiation: sk_OPENSSL_STRING_sort Unexecuted instantiation: sk_BIO_sort Unexecuted instantiation: sk_ASN1_INTEGER_sort Unexecuted instantiation: sk_ASN1_OBJECT_sort Unexecuted instantiation: sk_ASN1_TYPE_sort Unexecuted instantiation: sk_ASN1_VALUE_sort |
487 | | \ |
488 | 0 | OPENSSL_INLINE int sk_##name##_is_sorted(const STACK_OF(name) *sk) { \ |
489 | 0 | return OPENSSL_sk_is_sorted((const OPENSSL_STACK *)sk); \ |
490 | 0 | } \ Unexecuted instantiation: sk_void_is_sorted Unexecuted instantiation: sk_OPENSSL_STRING_is_sorted Unexecuted instantiation: sk_BIO_is_sorted Unexecuted instantiation: sk_ASN1_INTEGER_is_sorted Unexecuted instantiation: sk_ASN1_OBJECT_is_sorted Unexecuted instantiation: sk_ASN1_TYPE_is_sorted Unexecuted instantiation: sk_ASN1_VALUE_is_sorted |
491 | | \ |
492 | | OPENSSL_INLINE sk_##name##_cmp_func sk_##name##_set_cmp_func( \ |
493 | 0 | STACK_OF(name) *sk, sk_##name##_cmp_func comp) { \ |
494 | 0 | return (sk_##name##_cmp_func)OPENSSL_sk_set_cmp_func( \ |
495 | 0 | (OPENSSL_STACK *)sk, (OPENSSL_sk_cmp_func)comp); \ |
496 | 0 | } \ Unexecuted instantiation: sk_void_set_cmp_func Unexecuted instantiation: sk_OPENSSL_STRING_set_cmp_func Unexecuted instantiation: sk_BIO_set_cmp_func Unexecuted instantiation: sk_ASN1_INTEGER_set_cmp_func Unexecuted instantiation: sk_ASN1_OBJECT_set_cmp_func Unexecuted instantiation: sk_ASN1_TYPE_set_cmp_func Unexecuted instantiation: sk_ASN1_VALUE_set_cmp_func |
497 | | \ |
498 | | OPENSSL_INLINE STACK_OF(name) *sk_##name##_deep_copy( \ |
499 | | const STACK_OF(name) *sk, sk_##name##_copy_func copy_func, \ |
500 | 0 | sk_##name##_free_func free_func) { \ |
501 | 0 | return (STACK_OF(name) *)OPENSSL_sk_deep_copy( \ |
502 | 0 | (const OPENSSL_STACK *)sk, sk_##name##_call_copy_func, \ |
503 | 0 | (OPENSSL_sk_copy_func)copy_func, sk_##name##_call_free_func, \ |
504 | 0 | (OPENSSL_sk_free_func)free_func); \ |
505 | 0 | } \ Unexecuted instantiation: sk_void_deep_copy Unexecuted instantiation: sk_OPENSSL_STRING_deep_copy Unexecuted instantiation: sk_BIO_deep_copy Unexecuted instantiation: sk_ASN1_INTEGER_deep_copy Unexecuted instantiation: sk_ASN1_OBJECT_deep_copy Unexecuted instantiation: sk_ASN1_TYPE_deep_copy Unexecuted instantiation: sk_ASN1_VALUE_deep_copy |
506 | | \ |
507 | | OPENSSL_GNUC_CLANG_PRAGMA("GCC diagnostic pop") \ |
508 | | OPENSSL_MSVC_PRAGMA(warning(pop)) |
509 | | |
510 | | |
511 | | // Built-in stacks. |
512 | | |
513 | | typedef char *OPENSSL_STRING; |
514 | | |
515 | | DEFINE_STACK_OF(void) |
516 | | DEFINE_NAMED_STACK_OF(OPENSSL_STRING, char) |
517 | | |
518 | | |
519 | | #if defined(__cplusplus) |
520 | | } // extern C |
521 | | #endif |
522 | | |
523 | | #if !defined(BORINGSSL_NO_CXX) |
524 | | extern "C++" { |
525 | | |
526 | | #include <type_traits> |
527 | | |
528 | | BSSL_NAMESPACE_BEGIN |
529 | | |
530 | | namespace internal { |
531 | | |
532 | | // Stacks defined with |DEFINE_CONST_STACK_OF| are freed with |sk_free|. |
533 | | template <typename Stack> |
534 | | struct DeleterImpl<Stack, std::enable_if_t<StackTraits<Stack>::kIsConst>> { |
535 | | static void Free(Stack *sk) { |
536 | | OPENSSL_sk_free(reinterpret_cast<OPENSSL_STACK *>(sk)); |
537 | | } |
538 | | }; |
539 | | |
540 | | // Stacks defined with |DEFINE_STACK_OF| are freed with |sk_pop_free| and the |
541 | | // corresponding type's deleter. |
542 | | template <typename Stack> |
543 | | struct DeleterImpl<Stack, std::enable_if_t<!StackTraits<Stack>::kIsConst>> { |
544 | | static void Free(Stack *sk) { |
545 | | // sk_FOO_pop_free is defined by macros and bound by name, so we cannot |
546 | | // access it from C++ here. |
547 | | using Type = typename StackTraits<Stack>::Type; |
548 | | OPENSSL_sk_pop_free_ex( |
549 | | reinterpret_cast<OPENSSL_STACK *>(sk), |
550 | | [](OPENSSL_sk_free_func /* unused */, void *ptr) { |
551 | | DeleterImpl<Type>::Free(reinterpret_cast<Type *>(ptr)); |
552 | | }, |
553 | | nullptr); |
554 | | } |
555 | | }; |
556 | | |
557 | | template <typename Stack> |
558 | | class StackIteratorImpl { |
559 | | public: |
560 | | using Type = typename StackTraits<Stack>::Type; |
561 | | // Iterators must be default-constructable. |
562 | | StackIteratorImpl() : sk_(nullptr), idx_(0) {} |
563 | | StackIteratorImpl(const Stack *sk, size_t idx) : sk_(sk), idx_(idx) {} |
564 | | |
565 | | bool operator==(StackIteratorImpl other) const { |
566 | | return sk_ == other.sk_ && idx_ == other.idx_; |
567 | | } |
568 | | bool operator!=(StackIteratorImpl other) const { |
569 | | return !(*this == other); |
570 | | } |
571 | | |
572 | | Type *operator*() const { |
573 | | return reinterpret_cast<Type *>( |
574 | | OPENSSL_sk_value(reinterpret_cast<const OPENSSL_STACK *>(sk_), idx_)); |
575 | | } |
576 | | |
577 | | StackIteratorImpl &operator++(/* prefix */) { |
578 | | idx_++; |
579 | | return *this; |
580 | | } |
581 | | |
582 | | StackIteratorImpl operator++(int /* postfix */) { |
583 | | StackIteratorImpl copy(*this); |
584 | | ++(*this); |
585 | | return copy; |
586 | | } |
587 | | |
588 | | private: |
589 | | const Stack *sk_; |
590 | | size_t idx_; |
591 | | }; |
592 | | |
593 | | template <typename Stack> |
594 | | using StackIterator = |
595 | | std::enable_if_t<StackTraits<Stack>::kIsStack, StackIteratorImpl<Stack>>; |
596 | | |
597 | | } // namespace internal |
598 | | |
599 | | // PushToStack pushes |elem| to |sk|. It returns true on success and false on |
600 | | // allocation failure. |
601 | | template <typename Stack> |
602 | | inline std::enable_if_t<!internal::StackTraits<Stack>::kIsConst, bool> |
603 | | PushToStack(Stack *sk, |
604 | | UniquePtr<typename internal::StackTraits<Stack>::Type> elem) { |
605 | | if (!OPENSSL_sk_push(reinterpret_cast<OPENSSL_STACK *>(sk), elem.get())) { |
606 | | return false; |
607 | | } |
608 | | // OPENSSL_sk_push takes ownership on success. |
609 | | elem.release(); |
610 | | return true; |
611 | | } |
612 | | |
613 | | BSSL_NAMESPACE_END |
614 | | |
615 | | // Define begin() and end() for stack types so C++ range for loops work. |
616 | | template <typename Stack> |
617 | | inline bssl::internal::StackIterator<Stack> begin(const Stack *sk) { |
618 | | return bssl::internal::StackIterator<Stack>(sk, 0); |
619 | | } |
620 | | |
621 | | template <typename Stack> |
622 | | inline bssl::internal::StackIterator<Stack> end(const Stack *sk) { |
623 | | return bssl::internal::StackIterator<Stack>( |
624 | | sk, OPENSSL_sk_num(reinterpret_cast<const OPENSSL_STACK *>(sk))); |
625 | | } |
626 | | |
627 | | } // extern C++ |
628 | | #endif |
629 | | |
630 | | #endif // OPENSSL_HEADER_STACK_H |