/[svn]/libgig/trunk/src/helper.h
ViewVC logotype

Annotation of /libgig/trunk/src/helper.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3859 - (hide annotations) (download) (as text)
Sun Feb 14 14:21:55 2021 UTC (3 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 16467 byte(s)
* src/helper.h: Fix compile error with GCC 9 due to ignored result value
  of vasprintf() function call.

* Bumped version (4.2.0.svn19).

1 schoenebeck 803 /***************************************************************************
2     * *
3 schoenebeck 933 * libgig - C++ cross-platform Gigasampler format file access library *
4 schoenebeck 803 * *
5 schoenebeck 3859 * Copyright (C) 2003-2021 by Christian Schoenebeck *
6 schoenebeck 803 * <cuse@users.sourceforge.net> *
7     * *
8     * This library is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This library 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 General Public License *
19     * along with this library; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #ifndef __LIBGIG_HELPER_H__
25     #define __LIBGIG_HELPER_H__
26    
27 schoenebeck 809 #include <string.h>
28 schoenebeck 803 #include <string>
29     #include <sstream>
30 schoenebeck 3185 #include <algorithm>
31 schoenebeck 3859 #include <assert.h>
32 schoenebeck 803
33 schoenebeck 3476 #if defined(WIN32) && !HAVE_CONFIG_H && !defined(_MSC_VER)
34 persson 1330 # include "../win32/libgig_private.h" // like config.h, automatically generated by Dev-C++
35     # define PACKAGE "libgig"
36     # define VERSION VER_STRING // VER_STRING defined in libgig_private.h
37     #endif // WIN32
38    
39 schoenebeck 3476 #if (HAVE_CONFIG_H /*&& !HAVE_VASPRINTF*/ && defined(WIN32)) || defined(_MSC_VER)
40 schoenebeck 3199 # include <stdarg.h>
41     int vasprintf(char** ret, const char* format, va_list arg);
42     #endif
43    
44 schoenebeck 3476 #if defined(_MSC_VER)
45     # if _MSC_VER < 1900
46     # error versions prior to msvc 2015 have not been tested
47     # else
48     # include <BaseTsd.h>
49     typedef SSIZE_T ssize_t;
50     # endif
51     #endif
52    
53 schoenebeck 929 #include "RIFF.h"
54    
55 schoenebeck 803 // *************** Helper Functions **************
56     // *
57    
58     template<class T> inline std::string ToString(T o) {
59     std::stringstream ss;
60     ss << o;
61     return ss.str();
62     }
63    
64 schoenebeck 3474 // Behaves as printf() just that it returns it as string instead of writing to stdout.
65     inline std::string strPrint(const char* fmt, ...) {
66     va_list args;
67     va_start(args, fmt);
68     char* buf = NULL;
69 schoenebeck 3859 const int n = vasprintf(&buf, fmt, args);
70     assert(n >= 0);
71     std::string res = (buf && n > 0) ? buf : "";
72 schoenebeck 3474 if (buf) free(buf);
73     va_end(args);
74     return res;
75     }
76    
77 schoenebeck 3185 inline std::string toLowerCase(std::string s) {
78     std::transform(s.begin(), s.end(), s.begin(), ::tolower);
79     return s;
80     }
81    
82 schoenebeck 809 inline long Min(long A, long B) {
83     return (A > B) ? B : A;
84     }
85    
86     inline long Abs(long val) {
87     return (val > 0) ? val : -val;
88     }
89    
90 schoenebeck 2912 inline void swapBytes_16(void* Word) {
91     uint8_t byteCache = *((uint8_t*) Word);
92     *((uint8_t*) Word) = *((uint8_t*) Word + 1);
93     *((uint8_t*) Word + 1) = byteCache;
94     }
95    
96     inline void swapBytes_32(void* Word) {
97     uint8_t byteCache = *((uint8_t*) Word);
98     *((uint8_t*) Word) = *((uint8_t*) Word + 3);
99     *((uint8_t*) Word + 3) = byteCache;
100     byteCache = *((uint8_t*) Word + 1);
101     *((uint8_t*) Word + 1) = *((uint8_t*) Word + 2);
102     *((uint8_t*) Word + 2) = byteCache;
103     }
104    
105     inline void swapBytes_64(void* Word) {
106     uint8_t byteCache = ((uint8_t*)Word)[0];
107     ((uint8_t*)Word)[0] = ((uint8_t*)Word)[7];
108     ((uint8_t*)Word)[7] = byteCache;
109     byteCache = ((uint8_t*)Word)[1];
110     ((uint8_t*)Word)[1] = ((uint8_t*)Word)[6];
111     ((uint8_t*)Word)[6] = byteCache;
112     byteCache = ((uint8_t*)Word)[2];
113     ((uint8_t*)Word)[2] = ((uint8_t*)Word)[5];
114     ((uint8_t*)Word)[5] = byteCache;
115     byteCache = ((uint8_t*)Word)[3];
116     ((uint8_t*)Word)[3] = ((uint8_t*)Word)[4];
117     ((uint8_t*)Word)[4] = byteCache;
118     }
119    
120     inline void swapBytes(void* Word, uint64_t WordSize) {
121     uint8_t byteCache;
122     uint64_t lo = 0, hi = WordSize - 1;
123     for (; lo < hi; hi--, lo++) {
124     byteCache = *((uint8_t*) Word + lo);
125     *((uint8_t*) Word + lo) = *((uint8_t*) Word + hi);
126     *((uint8_t*) Word + hi) = byteCache;
127     }
128     }
129    
130 schoenebeck 809 /**
131 persson 1179 * Stores a 16 bit integer in memory using little-endian format.
132     *
133     * @param pData - memory pointer
134     * @param data - integer to be stored
135     */
136     inline void store16(uint8_t* pData, uint16_t data) {
137     pData[0] = data;
138     pData[1] = data >> 8;
139     }
140    
141     /**
142     * Stores a 32 bit integer in memory using little-endian format.
143     *
144     * @param pData - memory pointer
145     * @param data - integer to be stored
146     */
147     inline void store32(uint8_t* pData, uint32_t data) {
148     pData[0] = data;
149     pData[1] = data >> 8;
150     pData[2] = data >> 16;
151     pData[3] = data >> 24;
152     }
153    
154     /**
155 schoenebeck 3730 * Stores a 64 bit integer in memory using little-endian format.
156     *
157     * @param pData - memory pointer
158     * @param data - integer to be stored
159     */
160     inline void store64(uint8_t* pData, uint64_t data) {
161     pData[0] = data;
162     pData[1] = data >> 8;
163     pData[2] = data >> 16;
164     pData[3] = data >> 24;
165     pData[4] = data >> 32;
166     pData[5] = data >> 40;
167     pData[6] = data >> 48;
168     pData[7] = data >> 56;
169     }
170    
171     /**
172 schoenebeck 3474 * Loads a 16 bit integer in memory using little-endian format.
173     *
174     * @param pData - memory pointer
175     * @returns 16 bit data word
176     */
177     inline uint16_t load16(uint8_t* pData) {
178     return uint16_t(pData[0]) |
179     uint16_t(pData[1]) << 8;
180     }
181    
182     /**
183 schoenebeck 2912 * Loads a 32 bit integer in memory using little-endian format.
184     *
185     * @param pData - memory pointer
186     * @returns 32 bit data word
187     */
188     inline uint32_t load32(uint8_t* pData) {
189     return uint32_t(pData[0]) |
190     uint32_t(pData[1]) << 8 |
191     uint32_t(pData[2]) << 16 |
192     uint32_t(pData[3]) << 24;
193     }
194    
195     /**
196 schoenebeck 809 * Swaps the order of the data words in the given memory area
197     * with a granularity given by \a WordSize.
198     *
199     * @param pData - pointer to the memory area to be swapped
200     * @param AreaSize - size of the memory area to be swapped (in bytes)
201     * @param WordSize - size of the data words (in bytes)
202     */
203     inline void SwapMemoryArea(void* pData, unsigned long AreaSize, uint WordSize) {
204 schoenebeck 1875 if (!AreaSize) return; // AreaSize==0 would cause a segfault here
205 schoenebeck 809 switch (WordSize) { // TODO: unefficient
206     case 1: {
207     uint8_t* pDst = (uint8_t*) pData;
208     uint8_t cache;
209     unsigned long lo = 0, hi = AreaSize - 1;
210     for (; lo < hi; hi--, lo++) {
211     cache = pDst[lo];
212     pDst[lo] = pDst[hi];
213     pDst[hi] = cache;
214     }
215     break;
216     }
217     case 2: {
218     uint16_t* pDst = (uint16_t*) pData;
219     uint16_t cache;
220     unsigned long lo = 0, hi = (AreaSize >> 1) - 1;
221     for (; lo < hi; hi--, lo++) {
222     cache = pDst[lo];
223     pDst[lo] = pDst[hi];
224     pDst[hi] = cache;
225     }
226     break;
227     }
228     case 4: {
229     uint32_t* pDst = (uint32_t*) pData;
230     uint32_t cache;
231     unsigned long lo = 0, hi = (AreaSize >> 2) - 1;
232     for (; lo < hi; hi--, lo++) {
233     cache = pDst[lo];
234     pDst[lo] = pDst[hi];
235     pDst[hi] = cache;
236     }
237     break;
238     }
239     default: {
240     uint8_t* pCache = new uint8_t[WordSize]; // TODO: unefficient
241     unsigned long lo = 0, hi = AreaSize - WordSize;
242     for (; lo < hi; hi -= WordSize, lo += WordSize) {
243     memcpy(pCache, (uint8_t*) pData + lo, WordSize);
244     memcpy((uint8_t*) pData + lo, (uint8_t*) pData + hi, WordSize);
245     memcpy((uint8_t*) pData + hi, pCache, WordSize);
246     }
247 schoenebeck 1875 if (pCache) delete[] pCache;
248 schoenebeck 809 break;
249     }
250     }
251     }
252    
253 schoenebeck 929 /** @brief Load given info field (string).
254     *
255     * Load info field string from given info chunk (\a ck) and save value to \a s.
256     */
257     inline void LoadString(RIFF::Chunk* ck, std::string& s) {
258     if (ck) {
259     const char* str = (char*)ck->LoadChunkData();
260 schoenebeck 3348 if (!str) {
261     ck->ReleaseChunkData();
262     s = "";
263     return;
264     }
265 schoenebeck 3053 int size = (int) ck->GetSize();
266 schoenebeck 929 int len;
267     for (len = 0 ; len < size ; len++)
268     if (str[len] == '\0') break;
269     s.assign(str, len);
270     ck->ReleaseChunkData();
271     }
272     }
273    
274     /** @brief Apply given INFO field to the respective chunk.
275     *
276     * Apply given info value string to given info chunk, which is a
277     * subchunk of INFO list chunk \a lstINFO. If the given chunk already
278     * exists, value \a s will be applied. Otherwise if it doesn't exist yet
279     * and either \a s or \a sDefault is not an empty string, such a chunk
280     * will be created and either \a s or \a sDefault will be applied
281     * (depending on which one is not an empty string, if both are not an
282     * empty string \a s will be preferred).
283     *
284     * @param ChunkID - 32 bit RIFF chunk ID of INFO subchunk (only used in case \a ck is NULL)
285     * @param ck - INFO (sub)chunk where string should be stored to
286     * @param lstINFO - parent (INFO) RIFF list chunk
287     * @param s - current value of info field
288     * @param sDefault - default value
289     * @param bUseFixedLengthStrings - should a specific string size be forced in the chunk?
290     * @param size - wanted size of the INFO chunk. This is ignored if bUseFixedLengthStrings is false.
291     */
292     inline void SaveString(uint32_t ChunkID, RIFF::Chunk* ck, RIFF::List* lstINFO, const std::string& s, const std::string& sDefault, bool bUseFixedLengthStrings, int size) {
293     if (ck) { // if chunk exists already, use 's' as value
294 schoenebeck 3053 if (!bUseFixedLengthStrings) size = (int) s.size() + 1;
295 schoenebeck 929 ck->Resize(size);
296     char* pData = (char*) ck->LoadChunkData();
297     strncpy(pData, s.c_str(), size);
298 persson 1180 } else if (s != "" || sDefault != "" || bUseFixedLengthStrings) { // create chunk
299 schoenebeck 929 const std::string& sToSave = (s != "") ? s : sDefault;
300 schoenebeck 3053 if (!bUseFixedLengthStrings) size = (int) sToSave.size() + 1;
301 schoenebeck 929 ck = lstINFO->AddSubChunk(ChunkID, size);
302     char* pData = (char*) ck->LoadChunkData();
303     strncpy(pData, sToSave.c_str(), size);
304     }
305     }
306    
307 schoenebeck 2682 // private helper function to convert progress of a subprocess into the global progress
308     inline void __notify_progress(RIFF::progress_t* pProgress, float subprogress) {
309     if (pProgress && pProgress->callback) {
310     const float totalrange = pProgress->__range_max - pProgress->__range_min;
311     const float totalprogress = pProgress->__range_min + subprogress * totalrange;
312     pProgress->factor = totalprogress;
313     pProgress->callback(pProgress); // now actually notify about the progress
314     }
315     }
316    
317     // private helper function to divide a progress into subprogresses
318     inline void __divide_progress(RIFF::progress_t* pParentProgress, RIFF::progress_t* pSubProgress, float totalTasks, float currentTask) {
319     if (pParentProgress && pParentProgress->callback) {
320     const float totalrange = pParentProgress->__range_max - pParentProgress->__range_min;
321     pSubProgress->callback = pParentProgress->callback;
322     pSubProgress->custom = pParentProgress->custom;
323     pSubProgress->__range_min = pParentProgress->__range_min + totalrange * currentTask / totalTasks;
324     pSubProgress->__range_max = pSubProgress->__range_min + totalrange / totalTasks;
325     }
326     }
327    
328 schoenebeck 3481 // private helper function to divide a progress into subprogresses
329     inline void __divide_progress(RIFF::progress_t* pParentProgress, RIFF::progress_t* pSubProgress, float total, float lo, float hi) {
330     if (pParentProgress && pParentProgress->callback) {
331     const float totalrange = pParentProgress->__range_max - pParentProgress->__range_min;
332     pSubProgress->callback = pParentProgress->callback;
333     pSubProgress->custom = pParentProgress->custom;
334     pSubProgress->__range_min = pParentProgress->__range_min + totalrange * (lo / total);
335     pSubProgress->__range_max = pSubProgress->__range_min + totalrange * ((hi-lo) / total);
336     }
337     }
338    
339 schoenebeck 3484
340     /*****************************************************************************
341     * Any problems with any of the following helper functions? *
342     * *
343     * Then please first have a look at their current TEST CASES at *
344     * src/testcases/HelperTest.cpp as basis for your modifications! *
345     *****************************************************************************/
346    
347    
348 schoenebeck 3483 /// Removes one or more consecutive occurences of @a needle from the end of @a haystack.
349     inline std::string strip2ndFromEndOf1st(const std::string haystack, char needle) {
350     if (haystack.empty()) return haystack;
351     if (*haystack.rbegin() != needle) return haystack;
352     for (int i = haystack.length() - 1; i >= 0; --i)
353     if (haystack[i] != needle)
354     return haystack.substr(0, i+1);
355     return "";
356     }
357    
358     #ifndef NATIVE_PATH_SEPARATOR
359     # ifdef _WIN32
360     # define NATIVE_PATH_SEPARATOR '\\'
361     # else
362     # define NATIVE_PATH_SEPARATOR '/'
363     # endif
364 schoenebeck 3474 #endif
365    
366     /**
367     * Returns the owning path of the given path (its parent path). So for example
368     * passing "/some/path" would return "/some".
369     */
370     inline std::string parentPath(const std::string path) {
371 schoenebeck 3483 if (path.empty()) return path;
372     std::string s = strip2ndFromEndOf1st(path, NATIVE_PATH_SEPARATOR);
373     if (s.empty()) {
374     s.push_back(NATIVE_PATH_SEPARATOR); // i.e. return "/"
375     return s;
376     }
377     #if defined(_WIN32)
378     if (s.length() == 2 && s[1] == ':')
379     return s;
380     #endif
381     std::size_t pos = s.find_last_of(NATIVE_PATH_SEPARATOR);
382     if (pos == std::string::npos) return "";
383     if (pos == 0) {
384     s = "";
385     s.push_back(NATIVE_PATH_SEPARATOR); // i.e. return "/"
386     return s;
387     }
388     return s.substr(0, pos);
389 schoenebeck 3474 }
390    
391     /**
392     * Returns the last (lowest) portion of the given path. So for example passing
393     * "/some/path" would return "path".
394     */
395     inline std::string lastPathComponent(const std::string path) {
396 schoenebeck 3483 #if defined(_WIN32)
397     if (path.length() == 2 && path[1] == ':')
398     return "";
399     #endif
400 schoenebeck 3474 std::size_t pos = path.find_last_of(NATIVE_PATH_SEPARATOR);
401     return (pos == std::string::npos) ? path : path.substr(pos+1);
402     }
403    
404     /**
405     * Returns the given path with the type extension being stripped from its end.
406     * So for example passing "/some/path.foo" would return "/some/path".
407     */
408     inline std::string pathWithoutExtension(const std::string path) {
409     std::size_t posSep = path.find_last_of(NATIVE_PATH_SEPARATOR);
410     std::size_t posBase = (posSep == std::string::npos) ? 0 : posSep+1;
411 schoenebeck 3483 std::size_t posDot = path.find_last_of(".");
412 schoenebeck 3474 return (posDot != std::string::npos && posDot > posBase)
413     ? path.substr(0, posDot) : path;
414     }
415    
416     /**
417     * Returns the type extension of the given path. So for example passing
418     * "/some/path.foo" would return "foo".
419     */
420     inline std::string extensionOfPath(const std::string path) {
421     std::size_t posSep = path.find_last_of(NATIVE_PATH_SEPARATOR);
422     std::size_t posBase = (posSep == std::string::npos) ? 0 : posSep+1;
423 schoenebeck 3483 std::size_t posDot = path.find_last_of(".");
424 schoenebeck 3474 return (posDot != std::string::npos && posDot > posBase)
425     ? path.substr(posDot+1) : "";
426     }
427    
428     /**
429     * Combines the two given paths with each other. So for example passing
430     * "/some/path" and "/another/one" would return "/some/path/another/one".
431     */
432     inline std::string concatPath(const std::string path1, const std::string path2) {
433     return (!path1.empty() && *(path1.rbegin()) != NATIVE_PATH_SEPARATOR &&
434     !path2.empty() && *(path2.begin()) != NATIVE_PATH_SEPARATOR)
435     ? path1 + NATIVE_PATH_SEPARATOR + path2
436     : path1 + path2;
437     }
438    
439 schoenebeck 3730 /**
440     * Returns a hex string representation of the binary data being passed.
441     */
442     inline std::string binToHexStr(const void* pData, size_t sz) {
443     std::string s;
444     for (size_t i = 0; i < sz; ++i) {
445     s += strPrint("%02x", ((const char*)pData)[i]);
446     }
447     return s;
448     }
449    
450 schoenebeck 803 #endif // __LIBGIG_HELPER_H__

  ViewVC Help
Powered by ViewVC