1 /**
2  * @file utils.cpp
3  * @brief Mega SDK various utilities and helper classes
4  *
5  * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
6  *
7  * This file is part of the MEGA SDK - Client Access Engine.
8  *
9  * Applications using the MEGA API must present a valid application key
10  * and comply with the the rules set forth in the Terms of Service.
11  *
12  * The MEGA SDK is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * @copyright Simplified (2-clause) BSD License.
17  *
18  * You should have received a copy of the license along with this
19  * program.
20  */
21 
22 #include "mega/utils.h"
23 #include "mega/logging.h"
24 #include "mega/megaclient.h"
25 #include "mega/base64.h"
26 #include "mega/serialize64.h"
27 #include "mega/filesystem.h"
28 
29 #include <iomanip>
30 
31 #if defined(_WIN32) && defined(_MSC_VER)
32 #include <sys/timeb.h>
33 #endif
34 
35 #ifdef __APPLE__
36 #include <sys/sysctl.h>
37 #endif
38 
39 namespace mega {
40 
toNodeHandle(handle nodeHandle)41 string toNodeHandle(handle nodeHandle)
42 {
43     char base64Handle[12];
44     Base64::btoa((byte*)&(nodeHandle), MegaClient::NODEHANDLE, base64Handle);
45     return string(base64Handle);
46 }
47 
toHandle(handle h)48 string toHandle(handle h)
49 {
50     char base64Handle[14];
51     Base64::btoa((byte*)&(h), sizeof h, base64Handle);
52     return string(base64Handle);
53 }
54 
CacheableWriter(string & d)55 CacheableWriter::CacheableWriter(string& d)
56     : dest(d)
57 {
58 }
59 
serializebinary(byte * data,size_t len)60 void CacheableWriter::serializebinary(byte* data, size_t len)
61 {
62     dest.append((char*)data, len);
63 }
64 
serializechunkmacs(const chunkmac_map & m)65 void CacheableWriter::serializechunkmacs(const chunkmac_map& m)
66 {
67     m.serialize(dest);
68 }
69 
serializecstr(const char * field,bool storeNull)70 void CacheableWriter::serializecstr(const char* field, bool storeNull)
71 {
72     unsigned short ll = (unsigned short)(field ? strlen(field) + (storeNull ? 1 : 0) : 0);
73     dest.append((char*)&ll, sizeof(ll));
74     dest.append(field, ll);
75 }
76 
serializepstr(const string * field)77 void CacheableWriter::serializepstr(const string* field)
78 {
79     unsigned short ll = (unsigned short)(field ? field->size() : 0);
80     dest.append((char*)&ll, sizeof(ll));
81     if (field) dest.append(field->data(), ll);
82 }
83 
serializestring(const string & field)84 void CacheableWriter::serializestring(const string& field)
85 {
86     unsigned short ll = (unsigned short)field.size();
87     dest.append((char*)&ll, sizeof(ll));
88     dest.append(field.data(), ll);
89 }
90 
serializecompressed64(int64_t field)91 void CacheableWriter::serializecompressed64(int64_t field)
92 {
93     byte buf[sizeof field+1];
94     dest.append((const char*)buf, Serialize64::serialize(buf, field));
95 }
96 
serializei64(int64_t field)97 void CacheableWriter::serializei64(int64_t field)
98 {
99     dest.append((char*)&field, sizeof(field));
100 }
101 
serializeu32(uint32_t field)102 void CacheableWriter::serializeu32(uint32_t field)
103 {
104     dest.append((char*)&field, sizeof(field));
105 }
106 
serializehandle(handle field)107 void CacheableWriter::serializehandle(handle field)
108 {
109     dest.append((char*)&field, sizeof(field));
110 }
111 
serializenodehandle(handle field)112 void CacheableWriter::serializenodehandle(handle field)
113 {
114     dest.append((const char*)&field, MegaClient::NODEHANDLE);
115 }
116 
serializefsfp(fsfp_t field)117 void CacheableWriter::serializefsfp(fsfp_t field)
118 {
119     dest.append((char*)&field, sizeof(field));
120 }
121 
serializebool(bool field)122 void CacheableWriter::serializebool(bool field)
123 {
124     dest.append((char*)&field, sizeof(field));
125 }
126 
serializebyte(byte field)127 void CacheableWriter::serializebyte(byte field)
128 {
129     dest.append((char*)&field, sizeof(field));
130 }
131 
serializedouble(double field)132 void CacheableWriter::serializedouble(double field)
133 {
134     dest.append((char*)&field, sizeof(field));
135 }
136 
serializeexpansionflags(bool b0,bool b1,bool b2,bool b3,bool b4,bool b5,bool b6,bool b7)137 void CacheableWriter::serializeexpansionflags(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7)
138 {
139     unsigned char b[8];
140     b[0] = b0;
141     b[1] = b1;
142     b[2] = b2;
143     b[3] = b3;
144     b[4] = b4;
145     b[5] = b5;
146     b[6] = b6;
147     b[7] = b7;
148     dest.append((char*)b, 8);
149 }
150 
151 
CacheableReader(const string & d)152 CacheableReader::CacheableReader(const string& d)
153     : ptr(d.data())
154     , end(ptr + d.size())
155     , fieldnum(0)
156 {
157 }
158 
eraseused(string & d)159 void CacheableReader::eraseused(string& d)
160 {
161     assert(end == d.data() + d.size());
162     d.erase(0, ptr - d.data());
163 }
164 
unserializecstr(string & s,bool removeNull)165 bool CacheableReader::unserializecstr(string& s, bool removeNull)
166 {
167     if (ptr + sizeof(unsigned short) > end)
168     {
169         return false;
170     }
171 
172     unsigned short len = MemAccess::get<unsigned short>(ptr);
173     ptr += sizeof(len);
174 
175     if (ptr + len > end)
176     {
177         return false;
178     }
179 
180     if (len)
181     {
182         s.assign(ptr, len - (removeNull ? 1 : 0));
183     }
184     ptr += len;
185     fieldnum += 1;
186     return true;
187 }
188 
189 
unserializestring(string & s)190 bool CacheableReader::unserializestring(string& s)
191 {
192     if (ptr + sizeof(unsigned short) > end)
193     {
194         return false;
195     }
196 
197     unsigned short len = MemAccess::get<unsigned short>(ptr);
198     ptr += sizeof(len);
199 
200     if (ptr + len > end)
201     {
202         return false;
203     }
204 
205     if (len)
206     {
207         s.assign(ptr, len);
208     }
209     ptr += len;
210     fieldnum += 1;
211     return true;
212 }
213 
unserializebinary(byte * data,size_t len)214 bool CacheableReader::unserializebinary(byte* data, size_t len)
215 {
216     if (ptr + len > end)
217     {
218         return false;
219     }
220 
221     memcpy(data, ptr, len);
222     ptr += len;
223     fieldnum += 1;
224     return true;
225 }
226 
227 
serialize(string & d) const228 void chunkmac_map::serialize(string& d) const
229 {
230     unsigned short ll = (unsigned short)size();
231     d.append((char*)&ll, sizeof(ll));
232     for (const_iterator it = begin(); it != end(); it++)
233     {
234         d.append((char*)&it->first, sizeof(it->first));
235         d.append((char*)&it->second, sizeof(it->second));
236     }
237 }
238 
unserialize(const char * & ptr,const char * end)239 bool chunkmac_map::unserialize(const char*& ptr, const char* end)
240 {
241     unsigned short ll;
242     if ((ptr + sizeof(ll) > end) || ptr + (ll = MemAccess::get<unsigned short>(ptr)) * (sizeof(m_off_t) + sizeof(ChunkMAC)) + sizeof(ll) > end)
243     {
244         return false;
245     }
246 
247     ptr += sizeof(ll);
248 
249     for (int i = 0; i < ll; i++)
250     {
251         m_off_t pos = MemAccess::get<m_off_t>(ptr);
252         ptr += sizeof(m_off_t);
253 
254         memcpy(&((*this)[pos]), ptr, sizeof(ChunkMAC));
255         ptr += sizeof(ChunkMAC);
256     }
257     return true;
258 }
259 
calcprogress(m_off_t size,m_off_t & chunkpos,m_off_t & progresscompleted,m_off_t * lastblockprogress)260 void chunkmac_map::calcprogress(m_off_t size, m_off_t& chunkpos, m_off_t& progresscompleted, m_off_t* lastblockprogress)
261 {
262     chunkpos = 0;
263     progresscompleted = 0;
264 
265     for (chunkmac_map::iterator it = begin(); it != end(); ++it)
266     {
267         m_off_t chunkceil = ChunkedHash::chunkceil(it->first, size);
268 
269         if (chunkpos == it->first && it->second.finished)
270         {
271             chunkpos = chunkceil;
272             progresscompleted = chunkceil;
273         }
274         else if (it->second.finished)
275         {
276             m_off_t chunksize = chunkceil - ChunkedHash::chunkfloor(it->first);
277             progresscompleted += chunksize;
278         }
279         else
280         {
281             progresscompleted += it->second.offset;
282             if (lastblockprogress)
283             {
284                 *lastblockprogress += it->second.offset;
285             }
286         }
287     }
288 }
289 
nextUnprocessedPosFrom(m_off_t pos)290 m_off_t chunkmac_map::nextUnprocessedPosFrom(m_off_t pos)
291 {
292     for (const_iterator it = find(ChunkedHash::chunkfloor(pos));
293         it != end();
294         it = find(ChunkedHash::chunkfloor(pos)))
295     {
296         if (it->second.finished)
297         {
298             pos = ChunkedHash::chunkceil(pos);
299         }
300         else
301         {
302             pos += it->second.offset;
303             break;
304         }
305     }
306     return pos;
307 }
308 
expandUnprocessedPiece(m_off_t pos,m_off_t npos,m_off_t fileSize,m_off_t maxReqSize)309 m_off_t chunkmac_map::expandUnprocessedPiece(m_off_t pos, m_off_t npos, m_off_t fileSize, m_off_t maxReqSize)
310 {
311     for (iterator it = find(npos);
312         npos < fileSize && (npos - pos) <= maxReqSize && (it == end() || (!it->second.finished && !it->second.offset));
313         it = find(npos))
314     {
315         npos = ChunkedHash::chunkceil(npos, fileSize);
316     }
317     return npos;
318 }
319 
finishedUploadChunks(chunkmac_map & macs)320 void chunkmac_map::finishedUploadChunks(chunkmac_map& macs)
321 {
322     for (auto& m : macs)
323     {
324         m.second.finished = true;
325         (*this)[m.first] = m.second;
326         LOG_verbose << "Upload chunk completed: " << m.first;
327     }
328 }
329 
330 // coalesce block macs into file mac
macsmac(SymmCipher * cipher)331 int64_t chunkmac_map::macsmac(SymmCipher *cipher)
332 {
333     byte mac[SymmCipher::BLOCKSIZE] = { 0 };
334 
335     for (chunkmac_map::iterator it = begin(); it != end(); it++)
336     {
337         assert(it->first == ChunkedHash::chunkfloor(it->first));
338         // LOG_debug << "macsmac input: " << it->first << ": " << Base64Str<sizeof it->second.mac>(it->second.mac);
339         SymmCipher::xorblock(it->second.mac, mac);
340         cipher->ecb_encrypt(mac);
341     }
342 
343     uint32_t* m = (uint32_t*)mac;
344 
345     m[0] ^= m[1];
346     m[1] = m[2] ^ m[3];
347 
348     return MemAccess::get<int64_t>((const char*)mac);
349 }
350 
unserializechunkmacs(chunkmac_map & m)351 bool CacheableReader::unserializechunkmacs(chunkmac_map& m)
352 {
353     if (m.unserialize(ptr, end))   // ptr is adjusted by reference
354     {
355         fieldnum += 1;
356         return true;
357     }
358     return false;
359 }
360 
unserializecompressed64(uint64_t & field)361 bool CacheableReader::unserializecompressed64(uint64_t& field)
362 {
363     int fieldSize;
364     if ((fieldSize = Serialize64::unserialize((byte*)ptr, static_cast<int>(end - ptr), &field)) < 0)
365     {
366         LOG_err << "Serialize64 unserialization failed - malformed field";
367         return false;
368     }
369     else
370     {
371         ptr += fieldSize;
372     }
373     return true;
374 }
375 
unserializei64(int64_t & field)376 bool CacheableReader::unserializei64(int64_t& field)
377 {
378     if (ptr + sizeof(int64_t) > end)
379     {
380         return false;
381     }
382     field = MemAccess::get<int64_t>(ptr);
383     ptr += sizeof(int64_t);
384     fieldnum += 1;
385     return true;
386 }
387 
unserializeu32(uint32_t & field)388 bool CacheableReader::unserializeu32(uint32_t& field)
389 {
390     if (ptr + sizeof(uint32_t) > end)
391     {
392         return false;
393     }
394     field = MemAccess::get<uint32_t>(ptr);
395     ptr += sizeof(uint32_t);
396     fieldnum += 1;
397     return true;
398 }
399 
unserializehandle(handle & field)400 bool CacheableReader::unserializehandle(handle& field)
401 {
402     if (ptr + sizeof(handle) > end)
403     {
404         return false;
405     }
406     field = MemAccess::get<handle>(ptr);
407     ptr += sizeof(handle);
408     fieldnum += 1;
409     return true;
410 }
411 
unserializenodehandle(handle & field)412 bool CacheableReader::unserializenodehandle(handle& field)
413 {
414     if (ptr + MegaClient::NODEHANDLE > end)
415     {
416         return false;
417     }
418     field = 0;
419     memcpy((char*)&field, ptr, MegaClient::NODEHANDLE);
420     ptr += MegaClient::NODEHANDLE;
421     fieldnum += 1;
422     return true;
423 }
424 
unserializefsfp(fsfp_t & field)425 bool CacheableReader::unserializefsfp(fsfp_t& field)
426 {
427     if (ptr + sizeof(fsfp_t) > end)
428     {
429         return false;
430     }
431     field = MemAccess::get<fsfp_t>(ptr);
432     ptr += sizeof(fsfp_t);
433     fieldnum += 1;
434     return true;
435 }
436 
unserializebool(bool & field)437 bool CacheableReader::unserializebool(bool& field)
438 {
439     if (ptr + sizeof(bool) > end)
440     {
441         return false;
442     }
443     field = MemAccess::get<bool>(ptr);
444     ptr += sizeof(bool);
445     fieldnum += 1;
446     return true;
447 }
448 
unserializebyte(byte & field)449 bool CacheableReader::unserializebyte(byte& field)
450 {
451     if (ptr + sizeof(byte) > end)
452     {
453         return false;
454     }
455     field = MemAccess::get<byte>(ptr);
456     ptr += sizeof(byte);
457     fieldnum += 1;
458     return true;
459 }
460 
unserializedouble(double & field)461 bool CacheableReader::unserializedouble(double& field)
462 {
463     if (ptr + sizeof(double) > end)
464     {
465         return false;
466     }
467     field = MemAccess::get<double>(ptr);
468     ptr += sizeof(double);
469     fieldnum += 1;
470     return true;
471 }
472 
unserializeexpansionflags(unsigned char field[8],unsigned usedFlagCount)473 bool CacheableReader::unserializeexpansionflags(unsigned char field[8], unsigned usedFlagCount)
474 {
475     if (ptr + 8 > end)
476     {
477         return false;
478     }
479     memcpy(field, ptr, 8);
480 
481     for (int i = usedFlagCount;  i < 8; i++ )
482     {
483         if (field[i])
484         {
485             LOG_err << "Unserialization failed in expansion flags, invalid version detected.  Fieldnum: " << fieldnum;
486             return false;
487         }
488     }
489 
490     ptr += 8;
491     fieldnum += 1;
492     return true;
493 }
494 
495 #ifdef ENABLE_CHAT
TextChat()496 TextChat::TextChat()
497 {
498     id = UNDEF;
499     priv = PRIV_UNKNOWN;
500     shard = -1;
501     userpriv = NULL;
502     group = false;
503     ou = UNDEF;
504     resetTag();
505     ts = 0;
506     flags = 0;
507     publicchat = false;
508 
509     memset(&changed, 0, sizeof(changed));
510 }
511 
~TextChat()512 TextChat::~TextChat()
513 {
514     delete userpriv;
515 }
516 
serialize(string * d)517 bool TextChat::serialize(string *d)
518 {
519     unsigned short ll;
520 
521     d->append((char*)&id, sizeof id);
522     d->append((char*)&priv, sizeof priv);
523     d->append((char*)&shard, sizeof shard);
524 
525     ll = (unsigned short)(userpriv ? userpriv->size() : 0);
526     d->append((char*)&ll, sizeof ll);
527     if (userpriv)
528     {
529         userpriv_vector::iterator it = userpriv->begin();
530         while (it != userpriv->end())
531         {
532             handle uh = it->first;
533             d->append((char*)&uh, sizeof uh);
534 
535             privilege_t priv = it->second;
536             d->append((char*)&priv, sizeof priv);
537 
538             it++;
539         }
540     }
541 
542     d->append((char*)&group, sizeof group);
543 
544     // title is a binary array
545     ll = (unsigned short)title.size();
546     d->append((char*)&ll, sizeof ll);
547     d->append(title.data(), ll);
548 
549     d->append((char*)&ou, sizeof ou);
550     d->append((char*)&ts, sizeof(ts));
551 
552     char hasAttachments = attachedNodes.size() != 0;
553     d->append((char*)&hasAttachments, 1);
554 
555     d->append((char*)&flags, 1);
556 
557     char mode = publicchat ? 1 : 0;
558     d->append((char*)&mode, 1);
559 
560     char hasUnifiedKey = unifiedKey.size() ? 1 : 0;
561     d->append((char *)&hasUnifiedKey, 1);
562 
563     d->append("\0\0\0\0\0\0", 6); // additional bytes for backwards compatibility
564 
565     if (hasAttachments)
566     {
567         ll = (unsigned short)attachedNodes.size();  // number of nodes with granted access
568         d->append((char*)&ll, sizeof ll);
569 
570         for (attachments_map::iterator it = attachedNodes.begin(); it != attachedNodes.end(); it++)
571         {
572             d->append((char*)&it->first, sizeof it->first); // nodehandle
573 
574             ll = (unsigned short)it->second.size(); // number of users with granted access to the node
575             d->append((char*)&ll, sizeof ll);
576             for (set<handle>::iterator ituh = it->second.begin(); ituh != it->second.end(); ituh++)
577             {
578                 d->append((char*)&(*ituh), sizeof *ituh);   // userhandle
579             }
580         }
581     }
582 
583     if (hasUnifiedKey)
584     {
585         ll = (unsigned short) unifiedKey.size();
586         d->append((char *)&ll, sizeof ll);
587         d->append((char*) unifiedKey.data(), unifiedKey.size());
588     }
589 
590     return true;
591 }
592 
unserialize(class MegaClient * client,string * d)593 TextChat* TextChat::unserialize(class MegaClient *client, string *d)
594 {
595     handle id;
596     privilege_t priv;
597     int shard;
598     userpriv_vector *userpriv = NULL;
599     bool group;
600     string title;   // byte array
601     handle ou;
602     m_time_t ts;
603     byte flags;
604     char hasAttachments;
605     attachments_map attachedNodes;
606     bool publicchat;
607     string unifiedKey;
608 
609     unsigned short ll;
610     const char* ptr = d->data();
611     const char* end = ptr + d->size();
612 
613     if (ptr + sizeof(handle) + sizeof(privilege_t) + sizeof(int) + sizeof(short) > end)
614     {
615         return NULL;
616     }
617 
618     id = MemAccess::get<handle>(ptr);
619     ptr += sizeof id;
620 
621     priv = MemAccess::get<privilege_t>(ptr);
622     ptr += sizeof priv;
623 
624     shard = MemAccess::get<int>(ptr);
625     ptr += sizeof shard;
626 
627     ll = MemAccess::get<unsigned short>(ptr);
628     ptr += sizeof ll;
629     if (ll)
630     {
631         if (ptr + ll * (sizeof(handle) + sizeof(privilege_t)) > end)
632         {
633             return NULL;
634         }
635 
636         userpriv = new userpriv_vector();
637 
638         for (unsigned short i = 0; i < ll; i++)
639         {
640             handle uh = MemAccess::get<handle>(ptr);
641             ptr += sizeof uh;
642 
643             privilege_t priv = MemAccess::get<privilege_t>(ptr);
644             ptr += sizeof priv;
645 
646             userpriv->push_back(userpriv_pair(uh, priv));
647         }
648 
649         if (priv == PRIV_RM)    // clear peerlist if removed
650         {
651             delete userpriv;
652             userpriv = NULL;
653         }
654     }
655 
656     if (ptr + sizeof(bool) + sizeof(unsigned short) > end)
657     {
658         delete userpriv;
659         return NULL;
660     }
661 
662     group = MemAccess::get<bool>(ptr);
663     ptr += sizeof group;
664 
665     ll = MemAccess::get<unsigned short>(ptr);
666     ptr += sizeof ll;
667     if (ll)
668     {
669         if (ptr + ll > end)
670         {
671             delete userpriv;
672             return NULL;
673         }
674         title.assign(ptr, ll);
675     }
676     ptr += ll;
677 
678     if (ptr + sizeof(handle) + sizeof(m_time_t) + sizeof(char) + 9 > end)
679     {
680         delete userpriv;
681         return NULL;
682     }
683 
684     ou = MemAccess::get<handle>(ptr);
685     ptr += sizeof ou;
686 
687     ts = MemAccess::get<m_time_t>(ptr);
688     ptr += sizeof(m_time_t);
689 
690     hasAttachments = MemAccess::get<char>(ptr);
691     ptr += sizeof hasAttachments;
692 
693     flags = MemAccess::get<char>(ptr);
694     ptr += sizeof(char);
695 
696     char mode = MemAccess::get<char>(ptr);
697     publicchat = (mode == 1);
698     ptr += sizeof(char);
699 
700     char hasUnifiedKey = MemAccess::get<char>(ptr);
701     ptr += sizeof(char);
702 
703     for (int i = 6; i--;)
704     {
705         if (ptr + MemAccess::get<unsigned char>(ptr) < end)
706         {
707             ptr += MemAccess::get<unsigned char>(ptr) + 1;
708         }
709     }
710 
711     if (hasAttachments)
712     {
713         unsigned short numNodes = 0;
714         if (ptr + sizeof numNodes > end)
715         {
716             delete userpriv;
717             return NULL;
718         }
719 
720         numNodes = MemAccess::get<unsigned short>(ptr);
721         ptr += sizeof numNodes;
722 
723         for (int i = 0; i < numNodes; i++)
724         {
725             handle h = UNDEF;
726             unsigned short numUsers = 0;
727             if (ptr + sizeof h + sizeof numUsers > end)
728             {
729                 delete userpriv;
730                 return NULL;
731             }
732 
733             h = MemAccess::get<handle>(ptr);
734             ptr += sizeof h;
735 
736             numUsers = MemAccess::get<unsigned short>(ptr);
737             ptr += sizeof numUsers;
738 
739             handle uh = UNDEF;
740             if (ptr + (numUsers * sizeof(uh)) > end)
741             {
742                 delete userpriv;
743                 return NULL;
744             }
745 
746             for (int j = 0; j < numUsers; j++)
747             {
748                 uh = MemAccess::get<handle>(ptr);
749                 ptr += sizeof uh;
750 
751                 attachedNodes[h].insert(uh);
752             }
753         }
754     }
755 
756     if (hasUnifiedKey)
757     {
758         unsigned short keylen = 0;
759         if (ptr + sizeof keylen > end)
760         {
761             delete userpriv;
762             return NULL;
763         }
764 
765         keylen = MemAccess::get<unsigned short>(ptr);
766         ptr += sizeof keylen;
767 
768         if (ptr + keylen > end)
769         {
770             delete userpriv;
771             return NULL;
772         }
773 
774         unifiedKey.assign(ptr, keylen);
775         ptr += keylen;
776     }
777 
778     if (ptr < end)
779     {
780         delete userpriv;
781         return NULL;
782     }
783 
784     if (client->chats.find(id) == client->chats.end())
785     {
786         client->chats[id] = new TextChat();
787     }
788     else
789     {
790         LOG_warn << "Unserialized a chat already in RAM";
791     }
792     TextChat* chat = client->chats[id];
793     chat->id = id;
794     chat->priv = priv;
795     chat->shard = shard;
796     chat->userpriv = userpriv;
797     chat->group = group;
798     chat->title = title;
799     chat->ou = ou;
800     chat->resetTag();
801     chat->ts = ts;
802     chat->flags = flags;
803     chat->attachedNodes = attachedNodes;
804     chat->publicchat = publicchat;
805     chat->unifiedKey = unifiedKey;
806 
807     memset(&chat->changed, 0, sizeof(chat->changed));
808 
809     return chat;
810 }
811 
setTag(int tag)812 void TextChat::setTag(int tag)
813 {
814     if (this->tag != 0)    // external changes prevail
815     {
816         this->tag = tag;
817     }
818 }
819 
getTag()820 int TextChat::getTag()
821 {
822     return tag;
823 }
824 
resetTag()825 void TextChat::resetTag()
826 {
827     tag = -1;
828 }
829 
setNodeUserAccess(handle h,handle uh,bool revoke)830 bool TextChat::setNodeUserAccess(handle h, handle uh, bool revoke)
831 {
832     if (revoke)
833     {
834         attachments_map::iterator uhit = attachedNodes.find(h);
835         if (uhit != attachedNodes.end())
836         {
837             uhit->second.erase(uh);
838             if (uhit->second.empty())
839             {
840                 attachedNodes.erase(h);
841                 changed.attachments = true;
842             }
843             return true;
844         }
845     }
846     else
847     {
848         attachedNodes[h].insert(uh);
849         changed.attachments = true;
850         return true;
851     }
852 
853     return false;
854 }
855 
setFlags(byte newFlags)856 bool TextChat::setFlags(byte newFlags)
857 {
858     if (flags == newFlags)
859     {
860         return false;
861     }
862 
863     flags = newFlags;
864     changed.flags = true;
865 
866     return true;
867 }
868 
isFlagSet(uint8_t offset) const869 bool TextChat::isFlagSet(uint8_t offset) const
870 {
871     return (flags >> offset) & 1U;
872 }
873 
setMode(bool publicchat)874 bool TextChat::setMode(bool publicchat)
875 {
876     if (this->publicchat == publicchat)
877     {
878         return false;
879     }
880 
881     this->publicchat = publicchat;
882     changed.mode = true;
883 
884     return true;
885 }
886 
setFlag(bool value,uint8_t offset)887 bool TextChat::setFlag(bool value, uint8_t offset)
888 {
889     if (bool((flags >> offset) & 1U) == value)
890     {
891         return false;
892     }
893 
894     flags ^= (1U << offset);
895     changed.flags = true;
896 
897     return true;
898 }
899 #endif
900 
901 /**
902  * @brief Encrypts a string after padding it to block length.
903  *
904  * Note: With an IV, only use the first 8 bytes.
905  *
906  * @param data Data buffer to be encrypted. Encryption is done in-place,
907  *     so cipher text will be in `data` afterwards as well.
908  * @param key AES key for encryption.
909  * @param iv Optional initialisation vector for encryption. Will use a
910  *     zero IV if not given. If `iv` is a zero length string, a new IV
911  *     for encryption will be generated and available through the reference.
912  * @return Void.
913  */
encrypt(PrnGen & rng,string * data,SymmCipher * key,string * iv)914 void PaddedCBC::encrypt(PrnGen &rng, string* data, SymmCipher* key, string* iv)
915 {
916     if (iv)
917     {
918         // Make a new 8-byte IV, if the one passed is zero length.
919         if (iv->size() == 0)
920         {
921             byte* buf = new byte[8];
922             rng.genblock(buf, 8);
923             iv->append((char*)buf);
924             delete [] buf;
925         }
926 
927         // Truncate a longer IV to its first 8 bytes.
928         if (iv->size() > 8)
929         {
930             iv->resize(8);
931         }
932 
933         // Bring up the IV size to BLOCKSIZE.
934         iv->resize(key->BLOCKSIZE);
935     }
936 
937     // Pad to block size and encrypt.
938     data->append("E");
939     data->resize((data->size() + key->BLOCKSIZE - 1) & - key->BLOCKSIZE, 'P');
940     if (iv)
941     {
942         key->cbc_encrypt((byte*)data->data(), data->size(),
943                          (const byte*)iv->data());
944     }
945     else
946     {
947         key->cbc_encrypt((byte*)data->data(), data->size());
948     }
949 
950     // Truncate IV back to the first 8 bytes only..
951     if (iv)
952     {
953         iv->resize(8);
954     }
955 }
956 
957 /**
958  * @brief Decrypts a string and strips the padding.
959  *
960  * Note: With an IV, only use the first 8 bytes.
961  *
962  * @param data Data buffer to be decrypted. Decryption is done in-place,
963  *     so plain text will be in `data` afterwards as well.
964  * @param key AES key for decryption.
965  * @param iv Optional initialisation vector for encryption. Will use a
966  *     zero IV if not given.
967  * @return Void.
968  */
decrypt(string * data,SymmCipher * key,string * iv)969 bool PaddedCBC::decrypt(string* data, SymmCipher* key, string* iv)
970 {
971     if (iv)
972     {
973         // Truncate a longer IV to its first 8 bytes.
974         if (iv->size() > 8)
975         {
976             iv->resize(8);
977         }
978 
979         // Bring up the IV size to BLOCKSIZE.
980         iv->resize(key->BLOCKSIZE);
981     }
982 
983     if ((data->size() & (key->BLOCKSIZE - 1)))
984     {
985         return false;
986     }
987 
988     // Decrypt and unpad.
989     if (iv)
990     {
991         key->cbc_decrypt((byte*)data->data(), data->size(),
992                          (const byte*)iv->data());
993     }
994     else
995     {
996         key->cbc_decrypt((byte*)data->data(), data->size());
997     }
998 
999     size_t p = data->find_last_of('E');
1000 
1001     if (p == string::npos)
1002     {
1003         return false;
1004     }
1005 
1006     data->resize(p);
1007 
1008     return true;
1009 }
1010 
1011 // start of chunk
chunkfloor(m_off_t p)1012 m_off_t ChunkedHash::chunkfloor(m_off_t p)
1013 {
1014     m_off_t cp, np;
1015 
1016     cp = 0;
1017 
1018     for (unsigned i = 1; i <= 8; i++)
1019     {
1020         np = cp + i * SEGSIZE;
1021 
1022         if ((p >= cp) && (p < np))
1023         {
1024             return cp;
1025         }
1026 
1027         cp = np;
1028     }
1029 
1030     return ((p - cp) & - (8 * SEGSIZE)) + cp;
1031 }
1032 
1033 // end of chunk (== start of next chunk)
chunkceil(m_off_t p,m_off_t limit)1034 m_off_t ChunkedHash::chunkceil(m_off_t p, m_off_t limit)
1035 {
1036     m_off_t cp, np;
1037 
1038     cp = 0;
1039 
1040     for (unsigned i = 1; i <= 8; i++)
1041     {
1042         np = cp + i * SEGSIZE;
1043 
1044         if ((p >= cp) && (p < np))
1045         {
1046             return (limit < 0 || np < limit) ? np : limit;
1047         }
1048 
1049         cp = np;
1050     }
1051 
1052     np = ((p - cp) & - (8 * SEGSIZE)) + cp + 8 * SEGSIZE;
1053     return (limit < 0 || np < limit) ? np : limit;
1054 }
1055 
1056 
1057 // cryptographic signature generation/verification
HashSignature(Hash * h)1058 HashSignature::HashSignature(Hash* h)
1059 {
1060     hash = h;
1061 }
1062 
~HashSignature()1063 HashSignature::~HashSignature()
1064 {
1065     delete hash;
1066 }
1067 
add(const byte * data,unsigned len)1068 void HashSignature::add(const byte* data, unsigned len)
1069 {
1070     hash->add(data, len);
1071 }
1072 
get(AsymmCipher * privk,byte * sigbuf,unsigned sigbuflen)1073 unsigned HashSignature::get(AsymmCipher* privk, byte* sigbuf, unsigned sigbuflen)
1074 {
1075     string h;
1076 
1077     hash->get(&h);
1078 
1079     return privk->rawdecrypt((const byte*)h.data(), h.size(), sigbuf, sigbuflen);
1080 }
1081 
checksignature(AsymmCipher * pubk,const byte * sig,unsigned len)1082 bool HashSignature::checksignature(AsymmCipher* pubk, const byte* sig, unsigned len)
1083 {
1084     string h, s;
1085     unsigned size;
1086 
1087     hash->get(&h);
1088 
1089     s.resize(h.size());
1090 
1091     if (!(size = pubk->rawencrypt(sig, len, (byte*)s.data(), s.size())))
1092     {
1093         return 0;
1094     }
1095 
1096     if (size < h.size())
1097     {
1098         // left-pad with 0
1099         s.insert(0, h.size() - size, 0);
1100         s.resize(h.size());
1101     }
1102 
1103     return s == h;
1104 }
1105 
PayCrypter(PrnGen & rng)1106 PayCrypter::PayCrypter(PrnGen &rng)
1107     : rng(rng)
1108 {
1109     rng.genblock(keys, ENC_KEY_BYTES + MAC_KEY_BYTES);
1110     encKey = keys;
1111     hmacKey = keys+ENC_KEY_BYTES;
1112 
1113     rng.genblock(iv, IV_BYTES);
1114 }
1115 
setKeys(const byte * newEncKey,const byte * newHmacKey,const byte * newIv)1116 void PayCrypter::setKeys(const byte *newEncKey, const byte *newHmacKey, const byte *newIv)
1117 {
1118     memcpy(encKey, newEncKey, ENC_KEY_BYTES);
1119     memcpy(hmacKey, newHmacKey, MAC_KEY_BYTES);
1120     memcpy(iv, newIv, IV_BYTES);
1121 }
1122 
encryptPayload(const string * cleartext,string * result)1123 bool PayCrypter::encryptPayload(const string *cleartext, string *result)
1124 {
1125     //Check parameters
1126     if(!cleartext || !result)
1127     {
1128         return false;
1129     }
1130 
1131     //AES-CBC encryption
1132     string encResult;
1133     SymmCipher sym(encKey);
1134     sym.cbc_encrypt_pkcs_padding(cleartext, iv, &encResult);
1135 
1136     //Prepare the message to authenticate (IV + cipher text)
1137     string toAuthenticate((char *)iv, IV_BYTES);
1138     toAuthenticate.append(encResult);
1139 
1140     //HMAC-SHA256
1141     HMACSHA256 hmacProcessor(hmacKey, MAC_KEY_BYTES);
1142     hmacProcessor.add((byte *)toAuthenticate.data(), toAuthenticate.size());
1143     result->resize(32);
1144     hmacProcessor.get((byte *)result->data());
1145 
1146     //Complete the result (HMAC + IV - ciphertext)
1147     result->append((char *)iv, IV_BYTES);
1148     result->append(encResult);
1149     return true;
1150 }
1151 
rsaEncryptKeys(const string * cleartext,const byte * pubkdata,int pubkdatalen,string * result,bool randompadding)1152 bool PayCrypter::rsaEncryptKeys(const string *cleartext, const byte *pubkdata, int pubkdatalen, string *result, bool randompadding)
1153 {
1154     //Check parameters
1155     if(!cleartext || !pubkdata || !result)
1156     {
1157         return false;
1158     }
1159 
1160     //Create an AsymmCipher with the public key
1161     AsymmCipher asym;
1162     asym.setkey(AsymmCipher::PUBKEY, pubkdata, pubkdatalen);
1163 
1164     //Prepare the message to encrypt (2-byte header + clear text)
1165     string keyString;
1166     keyString.append(1, (byte)(cleartext->size() >> 8));
1167     keyString.append(1, (byte)(cleartext->size()));
1168     keyString.append(*cleartext);
1169 
1170     //Save the length of the valid message
1171     size_t keylen = keyString.size();
1172 
1173     //Resize to add padding
1174     keyString.resize(asym.key[AsymmCipher::PUB_PQ].ByteCount() - 2);
1175 
1176     //Add padding
1177     if(randompadding)
1178     {
1179         rng.genblock((byte *)keyString.data() + keylen, keyString.size() - keylen);
1180     }
1181 
1182     //RSA encryption
1183     result->resize(pubkdatalen);
1184     result->resize(asym.rawencrypt((byte *)keyString.data(), keyString.size(), (byte *)result->data(), result->size()));
1185 
1186     //Complete the result (2-byte header + RSA result)
1187     size_t reslen = result->size();
1188     result->insert(0, 1, (byte)(reslen >> 8));
1189     result->insert(1, 1, (byte)(reslen));
1190     return true;
1191 }
1192 
hybridEncrypt(const string * cleartext,const byte * pubkdata,int pubkdatalen,string * result,bool randompadding)1193 bool PayCrypter::hybridEncrypt(const string *cleartext, const byte *pubkdata, int pubkdatalen, string *result, bool randompadding)
1194 {
1195     if(!cleartext || !pubkdata || !result)
1196     {
1197         return false;
1198     }
1199 
1200     //Generate the payload
1201     string payloadString;
1202     encryptPayload(cleartext, &payloadString);
1203 
1204     //RSA encryption
1205     string rsaKeyCipher;
1206     string keysString;
1207     keysString.assign((char *)keys, ENC_KEY_BYTES + MAC_KEY_BYTES);
1208     rsaEncryptKeys(&keysString, pubkdata, pubkdatalen, &rsaKeyCipher, randompadding);
1209 
1210     //Complete the result
1211     *result = rsaKeyCipher + payloadString;
1212     return true;
1213 }
1214 
1215 #ifdef _WIN32
mega_snprintf(char * s,size_t n,const char * format,...)1216 int mega_snprintf(char *s, size_t n, const char *format, ...)
1217 {
1218     va_list args;
1219     int ret;
1220 
1221     if (!s || n <= 0)
1222     {
1223         return -1;
1224     }
1225 
1226     va_start(args, format);
1227     ret = vsnprintf(s, n, format, args);
1228     va_end(args);
1229 
1230     s[n - 1] = '\0';
1231     return ret;
1232 }
1233 #endif
1234 
tlvRecordsToContainer(PrnGen & rng,SymmCipher * key,encryptionsetting_t encSetting)1235 string * TLVstore::tlvRecordsToContainer(PrnGen &rng, SymmCipher *key, encryptionsetting_t encSetting)
1236 {
1237     // decide nonce/IV and auth. tag lengths based on the `mode`
1238     unsigned ivlen = TLVstore::getIvlen(encSetting);
1239     unsigned taglen = TLVstore::getTaglen(encSetting);
1240     encryptionmode_t encMode = TLVstore::getMode(encSetting);
1241 
1242     if (!ivlen || !taglen || encMode == AES_MODE_UNKNOWN)
1243     {
1244         return NULL;
1245     }
1246 
1247     // serialize the TLV records
1248     string *container = tlvRecordsToContainer();
1249 
1250     // generate IV array
1251     byte *iv = new byte[ivlen];
1252     rng.genblock(iv, ivlen);
1253 
1254     string cipherText;
1255 
1256     // encrypt the bytes using the specified mode
1257 
1258     if (encMode == AES_MODE_CCM)   // CCM or GCM_BROKEN (same than CCM)
1259     {
1260         key->ccm_encrypt(container, iv, ivlen, taglen, &cipherText);
1261     }
1262     else if (encMode == AES_MODE_GCM)   // then use GCM
1263     {
1264         key->gcm_encrypt(container, iv, ivlen, taglen, &cipherText);
1265     }
1266 
1267     string *result = new string;
1268     result->resize(1);
1269     result->at(0) = static_cast<char>(encSetting);
1270     result->append((char*) iv, ivlen);
1271     result->append((char*) cipherText.data(), cipherText.length()); // includes auth. tag
1272 
1273     delete [] iv;
1274     delete container;
1275 
1276     return result;
1277 }
1278 
tlvRecordsToContainer()1279 string* TLVstore::tlvRecordsToContainer()
1280 {
1281     string *result = new string;
1282     size_t offset = 0;
1283     size_t length;
1284 
1285     for (TLV_map::iterator it = tlv.begin(); it != tlv.end(); it++)
1286     {
1287         // copy Type
1288         result->append(it->first);
1289         offset += it->first.length() + 1;   // keep the NULL-char for Type string
1290 
1291         // set Length of value
1292         length = it->second.length();
1293         result->resize(offset + 2);
1294         result->at(offset) = static_cast<char>(length >> 8);
1295         result->at(offset + 1) = static_cast<char>(length & 0xFF);
1296         offset += 2;
1297 
1298         // copy the Value
1299         result->append((char*)it->second.data(), it->second.length());
1300         offset += it->second.length();
1301     }
1302 
1303     return result;
1304 }
1305 
get(string type) const1306 std::string TLVstore::get(string type) const
1307 {
1308     return tlv.at(type);
1309 }
1310 
getMap() const1311 const TLV_map * TLVstore::getMap() const
1312 {
1313     return &tlv;
1314 }
1315 
getKeys() const1316 vector<string> *TLVstore::getKeys() const
1317 {
1318     vector<string> *keys = new vector<string>;
1319     for (string_map::const_iterator it = tlv.begin(); it != tlv.end(); it++)
1320     {
1321         keys->push_back(it->first);
1322     }
1323     return keys;
1324 }
1325 
find(string type) const1326 bool TLVstore::find(string type) const
1327 {
1328     return (tlv.find(type) != tlv.end());
1329 }
1330 
set(string type,string value)1331 void TLVstore::set(string type, string value)
1332 {
1333     tlv[type] = value;
1334 }
1335 
reset(std::string type)1336 void TLVstore::reset(std::string type)
1337 {
1338     tlv.erase(type);
1339 }
1340 
size()1341 size_t TLVstore::size()
1342 {
1343     return tlv.size();
1344 }
1345 
getTaglen(int mode)1346 unsigned TLVstore::getTaglen(int mode)
1347 {
1348 
1349     switch (mode)
1350     {
1351     case AES_CCM_10_16:
1352     case AES_CCM_12_16:
1353     case AES_GCM_12_16_BROKEN:
1354     case AES_GCM_12_16:
1355         return 16;
1356 
1357     case AES_CCM_10_08:
1358     case AES_GCM_10_08_BROKEN:
1359     case AES_GCM_10_08:
1360         return 8;
1361 
1362     default:    // unknown block encryption mode
1363         return 0;
1364     }
1365 }
1366 
getIvlen(int mode)1367 unsigned TLVstore::getIvlen(int mode)
1368 {
1369     switch (mode)
1370     {
1371     case AES_CCM_12_16:
1372     case AES_GCM_12_16_BROKEN:
1373     case AES_GCM_12_16:
1374         return 12;
1375 
1376     case AES_CCM_10_08:
1377     case AES_GCM_10_08_BROKEN:
1378     case AES_CCM_10_16:
1379     case AES_GCM_10_08:
1380         return 10;
1381 
1382     default:    // unknown block encryption mode
1383         return 0;
1384     }
1385 }
1386 
getMode(int mode)1387 encryptionmode_t TLVstore::getMode(int mode)
1388 {
1389     switch (mode)
1390     {
1391     case AES_CCM_12_16:
1392     case AES_GCM_12_16_BROKEN:
1393     case AES_CCM_10_16:
1394     case AES_CCM_10_08:
1395     case AES_GCM_10_08_BROKEN:
1396         return AES_MODE_CCM;
1397 
1398     case AES_GCM_12_16:
1399     case AES_GCM_10_08:
1400         return AES_MODE_GCM;
1401 
1402     default:    // unknown block encryption mode
1403         return AES_MODE_UNKNOWN;
1404     }
1405 }
1406 
containerToTLVrecords(const string * data)1407 TLVstore * TLVstore::containerToTLVrecords(const string *data)
1408 {
1409     if (data->empty())
1410     {
1411         return NULL;
1412     }
1413 
1414     TLVstore *tlv = new TLVstore();
1415 
1416     size_t offset = 0;
1417 
1418     string type;
1419     size_t typelen;
1420     string value;
1421     unsigned valuelen;
1422     size_t pos;
1423 
1424     size_t datalen = data->length();
1425 
1426     while (offset < datalen)
1427     {
1428         // get the length of the Type string
1429         pos = data->find('\0', offset);
1430         typelen = pos - offset;
1431 
1432         // if no valid TLV record in the container, but remaining bytes...
1433         if (pos == string::npos || offset + typelen + 3 > datalen)
1434         {
1435             delete tlv;
1436             return NULL;
1437         }
1438 
1439         // get the Type string
1440         type.assign((char*)&(data->data()[offset]), typelen);
1441         offset += typelen + 1;        // +1: NULL character
1442 
1443         // get the Length of the value
1444         valuelen = (unsigned char)data->at(offset) << 8
1445                  | (unsigned char)data->at(offset + 1);
1446         offset += 2;
1447 
1448         // if there's not enough data for value...
1449         if (offset + valuelen > datalen)
1450         {
1451             delete tlv;
1452             return NULL;
1453         }
1454 
1455         // get the Value
1456         value.assign((char*)&(data->data()[offset]), valuelen);  // value may include NULL characters, read as a buffer
1457         offset += valuelen;
1458 
1459         // add it to the map
1460         tlv->set(type, value);
1461     }
1462 
1463     return tlv;
1464 }
1465 
1466 
containerToTLVrecords(const string * data,SymmCipher * key)1467 TLVstore * TLVstore::containerToTLVrecords(const string *data, SymmCipher *key)
1468 {
1469     if (data->empty())
1470     {
1471         return NULL;
1472     }
1473 
1474     unsigned offset = 0;
1475     encryptionsetting_t encSetting = (encryptionsetting_t) data->at(offset);
1476     offset++;
1477 
1478     unsigned ivlen = TLVstore::getIvlen(encSetting);
1479     unsigned taglen = TLVstore::getTaglen(encSetting);
1480     encryptionmode_t encMode = TLVstore::getMode(encSetting);
1481 
1482     if (encMode == AES_MODE_UNKNOWN || !ivlen || !taglen ||  data->size() < offset+ivlen+taglen)
1483     {
1484         return NULL;
1485     }
1486 
1487     byte *iv = new byte[ivlen];
1488     memcpy(iv, &(data->data()[offset]), ivlen);
1489     offset += ivlen;
1490 
1491     unsigned cipherTextLen = unsigned(data->length() - offset);
1492     string cipherText = data->substr(offset, cipherTextLen);
1493 
1494     unsigned clearTextLen = cipherTextLen - taglen;
1495     string clearText;
1496 
1497     bool decrypted = false;
1498     if (encMode == AES_MODE_CCM)   // CCM or GCM_BROKEN (same than CCM)
1499     {
1500        decrypted = key->ccm_decrypt(&cipherText, iv, ivlen, taglen, &clearText);
1501     }
1502     else if (encMode == AES_MODE_GCM)  // GCM
1503     {
1504        decrypted = key->gcm_decrypt(&cipherText, iv, ivlen, taglen, &clearText);
1505     }
1506 
1507     delete [] iv;
1508 
1509     if (!decrypted)  // the decryption has failed (probably due to authentication)
1510     {
1511         return NULL;
1512     }
1513     else if (clearText.empty()) // If decryption succeeded but attribute is empty, generate an empty TLV
1514     {
1515         return new TLVstore();
1516     }
1517 
1518     TLVstore *tlv = TLVstore::containerToTLVrecords(&clearText);
1519     if (!tlv) // 'data' might be affected by the legacy bug: strings encoded in UTF-8 instead of Unicode
1520     {
1521         // retry TLV decoding after conversion from 'UTF-8 chars' to 'Unicode chars'
1522         LOG_warn << "Retrying TLV records decoding with UTF-8 patch";
1523 
1524         string clearTextUnicode;
1525         if (!Utils::utf8toUnicode((const byte*)clearText.data(), clearTextLen, &clearTextUnicode))
1526         {
1527             LOG_err << "Invalid UTF-8 encoding";
1528         }
1529         else
1530         {
1531             tlv = TLVstore::containerToTLVrecords(&clearTextUnicode);
1532         }
1533     }
1534 
1535     return tlv;
1536 }
1537 
~TLVstore()1538 TLVstore::~TLVstore()
1539 {
1540 }
1541 
utf8SequenceSize(unsigned char c)1542 size_t Utils::utf8SequenceSize(unsigned char c)
1543 {
1544     int aux = static_cast<int>(c);
1545     if (aux >= 0 && aux <= 127)     return 1;
1546     else if ((aux & 0xE0) == 0xC0)  return 2;
1547     else if ((aux & 0xF0) == 0xE0)  return 3;
1548     else if ((aux & 0xF8) == 0xF0)  return 4;
1549     else
1550     {
1551         LOG_err << "Malformed UTF-8 sequence, interpret character " << c << " as literal";
1552         return 1;
1553     }
1554 }
1555 
utf8toUnicode(const uint8_t * src,unsigned srclen,string * result)1556 bool Utils::utf8toUnicode(const uint8_t *src, unsigned srclen, string *result)
1557 {
1558     uint8_t utf8cp1;
1559     uint8_t utf8cp2;
1560     int32_t unicodecp;
1561 
1562     if (!srclen)
1563     {
1564         result->clear();
1565         return true;
1566     }
1567 
1568     byte *res = new byte[srclen];
1569     unsigned rescount = 0;
1570 
1571     unsigned i = 0;
1572     while (i < srclen)
1573     {
1574         utf8cp1 = src[i++];
1575 
1576         if (utf8cp1 < 0x80)
1577         {
1578             res[rescount++] = utf8cp1;
1579         }
1580         else
1581         {
1582             if (i < srclen)
1583             {
1584                 utf8cp2 = src[i++];
1585 
1586                 // check codepoints are valid
1587                 if ((utf8cp1 == 0xC2 || utf8cp1 == 0xC3) && utf8cp2 >= 0x80 && utf8cp2 <= 0xBF)
1588                 {
1589                     unicodecp = ((utf8cp1 & 0x1F) <<  6) + (utf8cp2 & 0x3F);
1590                     res[rescount++] = unicodecp & 0xFF;
1591                 }
1592                 else
1593                 {
1594                     // error: one of the two-bytes UTF-8 char is not a valid UTF-8 char
1595                     delete [] res;
1596                     return false;
1597                 }
1598             }
1599             else
1600             {
1601                 // error: last byte indicates a two-bytes UTF-8 char, but only one left
1602                 delete [] res;
1603                 return false;
1604             }
1605         }
1606     }
1607 
1608     result->assign((const char*)res, rescount);
1609     delete [] res;
1610 
1611     return true;
1612 }
1613 
stringToHex(const std::string & input)1614 std::string Utils::stringToHex(const std::string &input)
1615 {
1616     static const char* const lut = "0123456789ABCDEF";
1617     size_t len = input.length();
1618 
1619     std::string output;
1620     output.reserve(2 * len);
1621     for (size_t i = 0; i < len; ++i)
1622     {
1623         const unsigned char c = input[i];
1624         output.push_back(lut[c >> 4]);
1625         output.push_back(lut[c & 15]);
1626     }
1627     return output;
1628 }
1629 
hexToString(const std::string & input)1630 std::string Utils::hexToString(const std::string &input)
1631 {
1632     static const char* const lut = "0123456789ABCDEF";
1633     size_t len = input.length();
1634     if (len & 1) throw std::invalid_argument("odd length");
1635 
1636     std::string output;
1637     output.reserve(len / 2);
1638     for (size_t i = 0; i < len; i += 2)
1639     {
1640         char a = input[i];
1641         const char* p = std::lower_bound(lut, lut + 16, a);
1642         if (*p != a) throw std::invalid_argument("not a hex digit");
1643 
1644         char b = input[i + 1];
1645         const char* q = std::lower_bound(lut, lut + 16, b);
1646         if (*q != b) throw std::invalid_argument("not a hex digit");
1647 
1648         output.push_back(static_cast<char>(((p - lut) << 4) | (q - lut)));
1649     }
1650     return output;
1651 }
1652 
abs(long long n)1653 long long abs(long long n)
1654 {
1655     // for pre-c++11 where this version is not defined yet
1656     return n >= 0 ? n : -n;
1657 }
1658 
m_localtime(m_time_t ttime,struct tm * dt)1659 struct tm* m_localtime(m_time_t ttime, struct tm *dt)
1660 {
1661     // works for 32 or 64 bit time_t
1662     time_t t = time_t(ttime);
1663 #if (__cplusplus >= 201103L) && defined (__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)
1664     localtime_s(&t, dt);
1665 #elif _MSC_VER >= 1400 || defined(__MINGW32__) // MSVCRT (2005+): std::localtime is threadsafe
1666     struct tm *newtm = localtime(&t);
1667     if (newtm)
1668     {
1669         memcpy(dt, newtm, sizeof(struct tm));
1670     }
1671     else
1672     {
1673         memset(dt, 0, sizeof(struct tm));
1674     }
1675 #elif _WIN32
1676 #error "localtime is not thread safe in this compiler; please use a later one"
1677 #else //POSIX
1678     localtime_r(&t, dt);
1679 #endif
1680     return dt;
1681 }
1682 
m_gmtime(m_time_t ttime,struct tm * dt)1683 struct tm* m_gmtime(m_time_t ttime, struct tm *dt)
1684 {
1685     // works for 32 or 64 bit time_t
1686     time_t t = time_t(ttime);
1687 #if (__cplusplus >= 201103L) && defined (__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)
1688     gmtime_s(&t, dt);
1689 #elif _MSC_VER >= 1400 || defined(__MINGW32__) // MSVCRT (2005+): std::gmtime is threadsafe
1690     struct tm *newtm = gmtime(&t);
1691     if (newtm)
1692     {
1693         memcpy(dt, newtm, sizeof(struct tm));
1694     }
1695     else
1696     {
1697         memset(dt, 0, sizeof(struct tm));
1698     }
1699 #elif _WIN32
1700 #error "gmtime is not thread safe in this compiler; please use a later one"
1701 #else //POSIX
1702     gmtime_r(&t, dt);
1703 #endif
1704     return dt;
1705 }
1706 
m_time(m_time_t * tt)1707 m_time_t m_time(m_time_t* tt)
1708 {
1709     // works for 32 or 64 bit time_t
1710     time_t t = time(NULL);
1711     if (tt)
1712     {
1713         *tt = t;
1714     }
1715     return t;
1716 }
1717 
m_mktime(struct tm * stm)1718 m_time_t m_mktime(struct tm* stm)
1719 {
1720     // works for 32 or 64 bit time_t
1721     return mktime(stm);
1722 }
1723 
m_clock_getmonotonictime(timespec * t)1724 int m_clock_getmonotonictime(timespec *t)
1725 {
1726 #ifdef __APPLE__
1727     struct timeval now;
1728     int rv = gettimeofday(&now, NULL);
1729     if (rv)
1730     {
1731         return rv;
1732     }
1733     t->tv_sec = now.tv_sec;
1734     t->tv_nsec = now.tv_usec * 1000;
1735     return 0;
1736 #elif defined(_WIN32) && defined(_MSC_VER)
1737     struct __timeb64 tb;
1738     _ftime64(&tb);
1739     t->tv_sec = tb.time;
1740     t->tv_nsec = long(tb.millitm) * 1000000;
1741     return 0;
1742 #else
1743 #ifdef CLOCK_BOOTTIME
1744     return clock_gettime(CLOCK_BOOTTIME, t);
1745 #else
1746     return clock_gettime(CLOCK_MONOTONIC, t);
1747 #endif
1748 #endif
1749 
1750 }
1751 
m_mktime_UTC(const struct tm * src)1752 m_time_t m_mktime_UTC(const struct tm *src)
1753 {
1754     struct tm dst = *src;
1755     m_time_t t = 0;
1756 #if _MSC_VER >= 1400 || defined(__MINGW32__) // MSVCRT (2005+)
1757     t = mktime(&dst);
1758     TIME_ZONE_INFORMATION TimeZoneInfo;
1759     GetTimeZoneInformation(&TimeZoneInfo);
1760     t += TimeZoneInfo.Bias * 60 - dst.tm_isdst * 3600;
1761 #elif _WIN32
1762 #error "localtime is not thread safe in this compiler; please use a later one"
1763 #else //POSIX
1764     t = mktime(&dst);
1765     t += dst.tm_gmtoff - dst.tm_isdst * 3600;
1766 #endif
1767     return t;
1768 }
1769 
rfc1123_datetime(time_t time)1770 std::string rfc1123_datetime( time_t time )
1771 {
1772     struct tm * timeinfo;
1773     char buffer [80];
1774     timeinfo = gmtime(&time);
1775     strftime (buffer, 80, "%a, %d %b %Y %H:%M:%S GMT",timeinfo);
1776     return buffer;
1777 }
1778 
webdavurlescape(const string & value)1779 string webdavurlescape(const string &value)
1780 {
1781     ostringstream escaped;
1782     escaped.fill('0');
1783     escaped << std::hex;
1784 
1785     for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i)
1786     {
1787         string::value_type c = (*i);
1788         if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/' || c == ':')
1789         {
1790             escaped << c;
1791         }
1792         else
1793         {
1794             escaped << std::uppercase;
1795             escaped << '%' << std::setw(2) << int((unsigned char) c);
1796             escaped << std::nouppercase;
1797         }
1798     }
1799 
1800     return escaped.str();
1801 }
1802 
escapewebdavchar(const char c)1803 string escapewebdavchar(const char c)
1804 {
1805     static bool unintitialized = true;
1806     static std::map<int,const char *> escapesec;
1807     if (unintitialized)
1808     {
1809         escapesec[33] = "&#33;"; // !  //For some reason &Exclamation; was not properly handled (crashed) by gvfsd-dav
1810         escapesec[34] = "&quot;"; // "
1811         escapesec[37] = "&percnt;"; // %
1812         escapesec[38] = "&amp;"; // &
1813         escapesec[39] = "&apos;"; // '
1814         escapesec[43] = "&add;"; // +
1815         escapesec[60] = "&lt;"; // <
1816         escapesec[61] = "&#61;"; // = //For some reason &equal; was not properly handled (crashed) by gvfsd-dav
1817         escapesec[62] = "&gt;"; // >
1818         escapesec[160] = "&nbsp;"; //NO-BREAK SPACE
1819         escapesec[161] = "&iexcl;"; //INVERTED EXCLAMATION MARK
1820         escapesec[162] = "&cent;"; //CENT SIGN
1821         escapesec[163] = "&pound;"; //POUND SIGN
1822         escapesec[164] = "&curren;"; //CURRENCY SIGN
1823         escapesec[165] = "&yen;"; //YEN SIGN
1824         escapesec[166] = "&brvbar;"; //BROKEN BAR
1825         escapesec[167] = "&sect;"; //SECTION SIGN
1826         escapesec[168] = "&uml;"; //DIAERESIS
1827         escapesec[169] = "&copy;"; //COPYRIGHT SIGN
1828         escapesec[170] = "&ordf;"; //FEMININE ORDINAL INDICATOR
1829         escapesec[171] = "&laquo;"; //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
1830         escapesec[172] = "&not;"; //NOT SIGN
1831         escapesec[173] = "&shy;"; //SOFT HYPHEN
1832         escapesec[174] = "&reg;"; //REGISTERED SIGN
1833         escapesec[175] = "&macr;"; //MACRON
1834         escapesec[176] = "&deg;"; //DEGREE SIGN
1835         escapesec[177] = "&plusmn;"; //PLUS-MINUS SIGN
1836         escapesec[178] = "&sup2;"; //SUPERSCRIPT TWO
1837         escapesec[179] = "&sup3;"; //SUPERSCRIPT THREE
1838         escapesec[180] = "&acute;"; //ACUTE ACCENT
1839         escapesec[181] = "&micro;"; //MICRO SIGN
1840         escapesec[182] = "&para;"; //PILCROW SIGN
1841         escapesec[183] = "&middot;"; //MIDDLE DOT
1842         escapesec[184] = "&cedil;"; //CEDILLA
1843         escapesec[185] = "&sup1;"; //SUPERSCRIPT ONE
1844         escapesec[186] = "&ordm;"; //MASCULINE ORDINAL INDICATOR
1845         escapesec[187] = "&raquo;"; //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
1846         escapesec[188] = "&frac14;"; //VULGAR FRACTION ONE QUARTER
1847         escapesec[189] = "&frac12;"; //VULGAR FRACTION ONE HALF
1848         escapesec[190] = "&frac34;"; //VULGAR FRACTION THREE QUARTERS
1849         escapesec[191] = "&iquest;"; //INVERTED QUESTION MARK
1850         escapesec[192] = "&Agrave;"; //LATIN CAPITAL LETTER A WITH GRAVE
1851         escapesec[193] = "&Aacute;"; //LATIN CAPITAL LETTER A WITH ACUTE
1852         escapesec[194] = "&Acirc;"; //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
1853         escapesec[195] = "&Atilde;"; //LATIN CAPITAL LETTER A WITH TILDE
1854         escapesec[196] = "&Auml;"; //LATIN CAPITAL LETTER A WITH DIAERESIS
1855         escapesec[197] = "&Aring;"; //LATIN CAPITAL LETTER A WITH RING ABOVE
1856         escapesec[198] = "&AElig;"; //LATIN CAPITAL LETTER AE
1857         escapesec[199] = "&Ccedil;"; //LATIN CAPITAL LETTER C WITH CEDILLA
1858         escapesec[200] = "&Egrave;"; //LATIN CAPITAL LETTER E WITH GRAVE
1859         escapesec[201] = "&Eacute;"; //LATIN CAPITAL LETTER E WITH ACUTE
1860         escapesec[202] = "&Ecirc;"; //LATIN CAPITAL LETTER E WITH CIRCUMFLEX
1861         escapesec[203] = "&Euml;"; //LATIN CAPITAL LETTER E WITH DIAERESIS
1862         escapesec[204] = "&Igrave;"; //LATIN CAPITAL LETTER I WITH GRAVE
1863         escapesec[205] = "&Iacute;"; //LATIN CAPITAL LETTER I WITH ACUTE
1864         escapesec[206] = "&Icirc;"; //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
1865         escapesec[207] = "&Iuml;"; //LATIN CAPITAL LETTER I WITH DIAERESIS
1866         escapesec[208] = "&ETH;"; //LATIN CAPITAL LETTER ETH
1867         escapesec[209] = "&Ntilde;"; //LATIN CAPITAL LETTER N WITH TILDE
1868         escapesec[210] = "&Ograve;"; //LATIN CAPITAL LETTER O WITH GRAVE
1869         escapesec[211] = "&Oacute;"; //LATIN CAPITAL LETTER O WITH ACUTE
1870         escapesec[212] = "&Ocirc;"; //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
1871         escapesec[213] = "&Otilde;"; //LATIN CAPITAL LETTER O WITH TILDE
1872         escapesec[214] = "&Ouml;"; //LATIN CAPITAL LETTER O WITH DIAERESIS
1873         escapesec[215] = "&times;"; //MULTIPLICATION SIGN
1874         escapesec[216] = "&Oslash;"; //LATIN CAPITAL LETTER O WITH STROKE
1875         escapesec[217] = "&Ugrave;"; //LATIN CAPITAL LETTER U WITH GRAVE
1876         escapesec[218] = "&Uacute;"; //LATIN CAPITAL LETTER U WITH ACUTE
1877         escapesec[219] = "&Ucirc;"; //LATIN CAPITAL LETTER U WITH CIRCUMFLEX
1878         escapesec[220] = "&Uuml;"; //LATIN CAPITAL LETTER U WITH DIAERESIS
1879         escapesec[221] = "&Yacute;"; //LATIN CAPITAL LETTER Y WITH ACUTE
1880         escapesec[222] = "&THORN;"; //LATIN CAPITAL LETTER THORN
1881         escapesec[223] = "&szlig;"; //LATIN SMALL LETTER SHARP S
1882         escapesec[224] = "&agrave;"; //LATIN SMALL LETTER A WITH GRAVE
1883         escapesec[225] = "&aacute;"; //LATIN SMALL LETTER A WITH ACUTE
1884         escapesec[226] = "&acirc;"; //LATIN SMALL LETTER A WITH CIRCUMFLEX
1885         escapesec[227] = "&atilde;"; //LATIN SMALL LETTER A WITH TILDE
1886         escapesec[228] = "&auml;"; //LATIN SMALL LETTER A WITH DIAERESIS
1887         escapesec[229] = "&aring;"; //LATIN SMALL LETTER A WITH RING ABOVE
1888         escapesec[230] = "&aelig;"; //LATIN SMALL LETTER AE
1889         escapesec[231] = "&ccedil;"; //LATIN SMALL LETTER C WITH CEDILLA
1890         escapesec[232] = "&egrave;"; //LATIN SMALL LETTER E WITH GRAVE
1891         escapesec[233] = "&eacute;"; //LATIN SMALL LETTER E WITH ACUTE
1892         escapesec[234] = "&ecirc;"; //LATIN SMALL LETTER E WITH CIRCUMFLEX
1893         escapesec[235] = "&euml;"; //LATIN SMALL LETTER E WITH DIAERESIS
1894         escapesec[236] = "&igrave;"; //LATIN SMALL LETTER I WITH GRAVE
1895         escapesec[237] = "&iacute;"; //LATIN SMALL LETTER I WITH ACUTE
1896         escapesec[238] = "&icirc;"; //LATIN SMALL LETTER I WITH CIRCUMFLEX
1897         escapesec[239] = "&iuml;"; //LATIN SMALL LETTER I WITH DIAERESIS
1898         escapesec[240] = "&eth;"; //LATIN SMALL LETTER ETH
1899         escapesec[241] = "&ntilde;"; //LATIN SMALL LETTER N WITH TILDE
1900         escapesec[242] = "&ograve;"; //LATIN SMALL LETTER O WITH GRAVE
1901         escapesec[243] = "&oacute;"; //LATIN SMALL LETTER O WITH ACUTE
1902         escapesec[244] = "&ocirc;"; //LATIN SMALL LETTER O WITH CIRCUMFLEX
1903         escapesec[245] = "&otilde;"; //LATIN SMALL LETTER O WITH TILDE
1904         escapesec[246] = "&ouml;"; //LATIN SMALL LETTER O WITH DIAERESIS
1905         escapesec[247] = "&divide;"; //DIVISION SIGN
1906         escapesec[248] = "&oslash;"; //LATIN SMALL LETTER O WITH STROKE
1907         escapesec[249] = "&ugrave;"; //LATIN SMALL LETTER U WITH GRAVE
1908         escapesec[250] = "&uacute;"; //LATIN SMALL LETTER U WITH ACUTE
1909         escapesec[251] = "&ucirc;"; //LATIN SMALL LETTER U WITH CIRCUMFLEX
1910         escapesec[252] = "&uuml;"; //LATIN SMALL LETTER U WITH DIAERESIS
1911         escapesec[253] = "&yacute;"; //LATIN SMALL LETTER Y WITH ACUTE
1912         escapesec[254] = "&thorn;"; //LATIN SMALL LETTER THORN
1913         escapesec[255] = "&yuml;"; //LATIN SMALL LETTER Y WITH DIAERESIS
1914         escapesec[338] = "&OElig;"; //LATIN CAPITAL LIGATURE OE
1915         escapesec[339] = "&oelig;"; //LATIN SMALL LIGATURE OE
1916         escapesec[352] = "&Scaron;"; //LATIN CAPITAL LETTER S WITH CARON
1917         escapesec[353] = "&scaron;"; //LATIN SMALL LETTER S WITH CARON
1918         escapesec[376] = "&Yuml;"; //LATIN CAPITAL LETTER Y WITH DIAERESIS
1919         escapesec[402] = "&fnof;"; //LATIN SMALL LETTER F WITH HOOK
1920         escapesec[710] = "&circ;"; //MODIFIER LETTER CIRCUMFLEX ACCENT
1921         escapesec[732] = "&tilde;"; //SMALL TILDE
1922         escapesec[913] = "&Alpha;"; //GREEK CAPITAL LETTER ALPHA
1923         escapesec[914] = "&Beta;"; //GREEK CAPITAL LETTER BETA
1924         escapesec[915] = "&Gamma;"; //GREEK CAPITAL LETTER GAMMA
1925         escapesec[916] = "&Delta;"; //GREEK CAPITAL LETTER DELTA
1926         escapesec[917] = "&Epsilon;"; //GREEK CAPITAL LETTER EPSILON
1927         escapesec[918] = "&Zeta;"; //GREEK CAPITAL LETTER ZETA
1928         escapesec[919] = "&Eta;"; //GREEK CAPITAL LETTER ETA
1929         escapesec[920] = "&Theta;"; //GREEK CAPITAL LETTER THETA
1930         escapesec[921] = "&Iota;"; //GREEK CAPITAL LETTER IOTA
1931         escapesec[922] = "&Kappa;"; //GREEK CAPITAL LETTER KAPPA
1932         escapesec[923] = "&Lambda;"; //GREEK CAPITAL LETTER LAMDA
1933         escapesec[924] = "&Mu;"; //GREEK CAPITAL LETTER MU
1934         escapesec[925] = "&Nu;"; //GREEK CAPITAL LETTER NU
1935         escapesec[926] = "&Xi;"; //GREEK CAPITAL LETTER XI
1936         escapesec[927] = "&Omicron;"; //GREEK CAPITAL LETTER OMICRON
1937         escapesec[928] = "&Pi;"; //GREEK CAPITAL LETTER PI
1938         escapesec[929] = "&Rho;"; //GREEK CAPITAL LETTER RHO
1939         escapesec[931] = "&Sigma;"; //GREEK CAPITAL LETTER SIGMA
1940         escapesec[932] = "&Tau;"; //GREEK CAPITAL LETTER TAU
1941         escapesec[933] = "&Upsilon;"; //GREEK CAPITAL LETTER UPSILON
1942         escapesec[934] = "&Phi;"; //GREEK CAPITAL LETTER PHI
1943         escapesec[935] = "&Chi;"; //GREEK CAPITAL LETTER CHI
1944         escapesec[936] = "&Psi;"; //GREEK CAPITAL LETTER PSI
1945         escapesec[937] = "&Omega;"; //GREEK CAPITAL LETTER OMEGA
1946         escapesec[945] = "&alpha;"; //GREEK SMALL LETTER ALPHA
1947         escapesec[946] = "&beta;"; //GREEK SMALL LETTER BETA
1948         escapesec[947] = "&gamma;"; //GREEK SMALL LETTER GAMMA
1949         escapesec[948] = "&delta;"; //GREEK SMALL LETTER DELTA
1950         escapesec[949] = "&epsilon;"; //GREEK SMALL LETTER EPSILON
1951         escapesec[950] = "&zeta;"; //GREEK SMALL LETTER ZETA
1952         escapesec[951] = "&eta;"; //GREEK SMALL LETTER ETA
1953         escapesec[952] = "&theta;"; //GREEK SMALL LETTER THETA
1954         escapesec[953] = "&iota;"; //GREEK SMALL LETTER IOTA
1955         escapesec[954] = "&kappa;"; //GREEK SMALL LETTER KAPPA
1956         escapesec[955] = "&lambda;"; //GREEK SMALL LETTER LAMDA
1957         escapesec[956] = "&mu;"; //GREEK SMALL LETTER MU
1958         escapesec[957] = "&nu;"; //GREEK SMALL LETTER NU
1959         escapesec[958] = "&xi;"; //GREEK SMALL LETTER XI
1960         escapesec[959] = "&omicron;"; //GREEK SMALL LETTER OMICRON
1961         escapesec[960] = "&pi;"; //GREEK SMALL LETTER PI
1962         escapesec[961] = "&rho;"; //GREEK SMALL LETTER RHO
1963         escapesec[962] = "&sigmaf;"; //GREEK SMALL LETTER FINAL SIGMA
1964         escapesec[963] = "&sigma;"; //GREEK SMALL LETTER SIGMA
1965         escapesec[964] = "&tau;"; //GREEK SMALL LETTER TAU
1966         escapesec[965] = "&upsilon;"; //GREEK SMALL LETTER UPSILON
1967         escapesec[966] = "&phi;"; //GREEK SMALL LETTER PHI
1968         escapesec[967] = "&chi;"; //GREEK SMALL LETTER CHI
1969         escapesec[968] = "&psi;"; //GREEK SMALL LETTER PSI
1970         escapesec[969] = "&omega;"; //GREEK SMALL LETTER OMEGA
1971         escapesec[977] = "&thetasym;"; //GREEK THETA SYMBOL
1972         escapesec[978] = "&upsih;"; //GREEK UPSILON WITH HOOK SYMBOL
1973         escapesec[982] = "&piv;"; //GREEK PI SYMBOL
1974         escapesec[8194] = "&ensp;"; //EN SPACE
1975         escapesec[8195] = "&emsp;"; //EM SPACE
1976         escapesec[8201] = "&thinsp;"; //THIN SPACE
1977         escapesec[8204] = "&zwnj;"; //ZERO WIDTH NON-JOINER
1978         escapesec[8205] = "&zwj;"; //ZERO WIDTH JOINER
1979         escapesec[8206] = "&lrm;"; //LEFT-TO-RIGHT MARK
1980         escapesec[8207] = "&rlm;"; //RIGHT-TO-LEFT MARK
1981         escapesec[8211] = "&ndash;"; //EN DASH
1982         escapesec[8212] = "&mdash;"; //EM DASH
1983         escapesec[8213] = "&horbar;"; //HORIZONTAL BAR
1984         escapesec[8216] = "&lsquo;"; //LEFT SINGLE QUOTATION MARK
1985         escapesec[8217] = "&rsquo;"; //RIGHT SINGLE QUOTATION MARK
1986         escapesec[8218] = "&sbquo;"; //SINGLE LOW-9 QUOTATION MARK
1987         escapesec[8220] = "&ldquo;"; //LEFT DOUBLE QUOTATION MARK
1988         escapesec[8221] = "&rdquo;"; //RIGHT DOUBLE QUOTATION MARK
1989         escapesec[8222] = "&bdquo;"; //DOUBLE LOW-9 QUOTATION MARK
1990         escapesec[8224] = "&dagger;"; //DAGGER
1991         escapesec[8225] = "&Dagger;"; //DOUBLE DAGGER
1992         escapesec[8226] = "&bull;"; //BULLET
1993         escapesec[8230] = "&hellip;"; //HORIZONTAL ELLIPSIS
1994         escapesec[8240] = "&permil;"; //PER MILLE SIGN
1995         escapesec[8242] = "&prime;"; //PRIME
1996         escapesec[8243] = "&Prime;"; //DOUBLE PRIME
1997         escapesec[8249] = "&lsaquo;"; //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
1998         escapesec[8250] = "&rsaquo;"; //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
1999         escapesec[8254] = "&oline;"; //OVERLINE
2000         escapesec[8260] = "&frasl;"; //FRACTION SLASH
2001         escapesec[8364] = "&euro;"; //EURO SIGN
2002         escapesec[8465] = "&image;"; //BLACK-LETTER CAPITAL I
2003         escapesec[8472] = "&weierp;"; //SCRIPT CAPITAL P
2004         escapesec[8476] = "&real;"; //BLACK-LETTER CAPITAL R
2005         escapesec[8482] = "&trade;"; //TRADE MARK SIGN
2006         escapesec[8501] = "&alefsym;"; //ALEF SYMBOL
2007         escapesec[8592] = "&larr;"; //LEFTWARDS ARROW
2008         escapesec[8593] = "&uarr;"; //UPWARDS ARROW
2009         escapesec[8594] = "&rarr;"; //RIGHTWARDS ARROW
2010         escapesec[8595] = "&darr;"; //DOWNWARDS ARROW
2011         escapesec[8596] = "&harr;"; //LEFT RIGHT ARROW
2012         escapesec[8629] = "&crarr;"; //DOWNWARDS ARROW WITH CORNER LEFTWARDS
2013         escapesec[8656] = "&lArr;"; //LEFTWARDS DOUBLE ARROW
2014         escapesec[8657] = "&uArr;"; //UPWARDS DOUBLE ARROW
2015         escapesec[8658] = "&rArr;"; //RIGHTWARDS DOUBLE ARROW
2016         escapesec[8659] = "&dArr;"; //DOWNWARDS DOUBLE ARROW
2017         escapesec[8660] = "&hArr;"; //LEFT RIGHT DOUBLE ARROW
2018         escapesec[8704] = "&forall;"; //FOR ALL
2019         escapesec[8706] = "&part;"; //PARTIAL DIFFERENTIAL
2020         escapesec[8707] = "&exist;"; //THERE EXISTS
2021         escapesec[8709] = "&empty;"; //EMPTY SET
2022         escapesec[8711] = "&nabla;"; //NABLA
2023         escapesec[8712] = "&isin;"; //ELEMENT OF
2024         escapesec[8713] = "&notin;"; //NOT AN ELEMENT OF
2025         escapesec[8715] = "&ni;"; //CONTAINS AS MEMBER
2026         escapesec[8719] = "&prod;"; //N-ARY PRODUCT
2027         escapesec[8721] = "&sum;"; //N-ARY SUMMATION
2028         escapesec[8722] = "&minus;"; //MINUS SIGN
2029         escapesec[8727] = "&lowast;"; //ASTERISK OPERATOR
2030         escapesec[8730] = "&radic;"; //SQUARE ROOT
2031         escapesec[8733] = "&prop;"; //PROPORTIONAL TO
2032         escapesec[8734] = "&infin;"; //INFINITY
2033         escapesec[8736] = "&ang;"; //ANGLE
2034         escapesec[8743] = "&and;"; //LOGICAL AND
2035         escapesec[8744] = "&or;"; //LOGICAL OR
2036         escapesec[8745] = "&cap;"; //INTERSECTION
2037         escapesec[8746] = "&cup;"; //UNION
2038         escapesec[8747] = "&int;"; //INTEGRAL
2039         escapesec[8756] = "&there4;"; //THEREFORE
2040         escapesec[8764] = "&sim;"; //TILDE OPERATOR
2041         escapesec[8773] = "&cong;"; //APPROXIMATELY EQUAL TO
2042         escapesec[8776] = "&asymp;"; //ALMOST EQUAL TO
2043         escapesec[8800] = "&ne;"; //NOT EQUAL TO
2044         escapesec[8801] = "&equiv;"; //IDENTICAL TO
2045         escapesec[8804] = "&le;"; //LESS-THAN OR EQUAL TO
2046         escapesec[8805] = "&ge;"; //GREATER-THAN OR EQUAL TO
2047         escapesec[8834] = "&sub;"; //SUBSET OF
2048         escapesec[8835] = "&sup;"; //SUPERSET OF
2049         escapesec[8836] = "&nsub;"; //NOT A SUBSET OF
2050         escapesec[8838] = "&sube;"; //SUBSET OF OR EQUAL TO
2051         escapesec[8839] = "&supe;"; //SUPERSET OF OR EQUAL TO
2052         escapesec[8853] = "&oplus;"; //CIRCLED PLUS
2053         escapesec[8855] = "&otimes;"; //CIRCLED TIMES
2054         escapesec[8869] = "&perp;"; //UP TACK
2055         escapesec[8901] = "&sdot;"; //DOT OPERATOR
2056         escapesec[8968] = "&lceil;"; //LEFT CEILING
2057         escapesec[8969] = "&rceil;"; //RIGHT CEILING
2058         escapesec[8970] = "&lfloor;"; //LEFT FLOOR
2059         escapesec[8971] = "&rfloor;"; //RIGHT FLOOR
2060         escapesec[9001] = "&lang;"; //LEFT-POINTING ANGLE BRACKET
2061         escapesec[9002] = "&rang;"; //RIGHT-POINTING ANGLE BRACKET
2062         escapesec[9674] = "&loz;"; //LOZENGE
2063         escapesec[9824] = "&spades;"; //BLACK SPADE SUIT
2064         escapesec[9827] = "&clubs;"; //BLACK CLUB SUIT
2065         escapesec[9829] = "&hearts;"; //BLACK HEART SUIT
2066         escapesec[9830] = "&diams;"; //BLACK DIAMOND SUIT
2067 
2068         unintitialized = false;
2069     }
2070     if (escapesec.find(c) != escapesec.end())
2071     {
2072         return escapesec[c];
2073     }
2074 
2075     return string(1,c);
2076 }
2077 
webdavnameescape(const string & value)2078 string webdavnameescape(const string &value) {
2079     ostringstream escaped;
2080 
2081     for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i)
2082     {
2083         escaped << escapewebdavchar(*i);
2084     }
2085 
2086     return escaped.str();
2087 }
2088 
tolower_string(std::string & str)2089 void tolower_string(std::string& str)
2090 {
2091     std::transform(str.begin(), str.end(), str.begin(), [](char c) {return static_cast<char>(::tolower(c)); });
2092 }
2093 
2094 #ifdef __APPLE__
macOSmajorVersion()2095 int macOSmajorVersion()
2096 {
2097     char releaseStr[256];
2098     size_t size = sizeof(releaseStr);
2099     if (!sysctlbyname("kern.osrelease", releaseStr, &size, NULL, 0)  && size > 0)
2100     {
2101         if (strchr(releaseStr,'.'))
2102         {
2103             char *token = strtok(releaseStr, ".");
2104             if (token)
2105             {
2106                 errno = 0;
2107                 char *endPtr = NULL;
2108                 long majorVersion = strtol(token, &endPtr, 10);
2109                 if (endPtr != token && errno != ERANGE && majorVersion >= INT_MIN && majorVersion <= INT_MAX)
2110                 {
2111                     return int(majorVersion);
2112                 }
2113             }
2114         }
2115     }
2116 
2117     return -1;
2118 }
2119 #endif
2120 
operator +=(const NodeCounter & o)2121 void NodeCounter::operator += (const NodeCounter& o)
2122 {
2123     storage += o.storage;
2124     versionStorage += o.versionStorage;
2125     files += o.files;
2126     folders += o.folders;
2127     versions += o.versions;
2128 }
2129 
operator -=(const NodeCounter & o)2130 void NodeCounter::operator -= (const NodeCounter& o)
2131 {
2132     storage -= o.storage;
2133     versionStorage -= o.versionStorage;
2134     files -= o.files;
2135     folders -= o.folders;
2136     versions -= o.versions;
2137 }
2138 
SyncConfig(std::string localPath,const handle remoteNode,const fsfp_t localFingerprint,std::vector<std::string> regExps,const Type syncType,const bool syncDeletions,const bool forceOverwrite)2139 SyncConfig::SyncConfig(std::string localPath,
2140                        const handle remoteNode,
2141                        const fsfp_t localFingerprint,
2142                        std::vector<std::string> regExps,
2143                        const Type syncType,
2144                        const bool syncDeletions,
2145                        const bool forceOverwrite)
2146     : mLocalPath{std::move(localPath)}
2147     , mRemoteNode{remoteNode}
2148     , mLocalFingerprint{localFingerprint}
2149     , mRegExps{std::move(regExps)}
2150     , mSyncType{syncType}
2151     , mSyncDeletions{syncDeletions}
2152     , mForceOverwrite{forceOverwrite}
2153 {}
2154 
isResumable() const2155 bool SyncConfig::isResumable() const
2156 {
2157     return mResumable;
2158 }
2159 
setResumable(bool resumable)2160 void SyncConfig::setResumable(bool resumable)
2161 {
2162     mResumable = resumable;
2163 }
2164 
getLocalPath() const2165 const std::string& SyncConfig::getLocalPath() const
2166 {
2167     return mLocalPath;
2168 }
2169 
getRemoteNode() const2170 handle SyncConfig::getRemoteNode() const
2171 {
2172     return mRemoteNode;
2173 }
2174 
getLocalFingerprint() const2175 handle SyncConfig::getLocalFingerprint() const
2176 {
2177     return mLocalFingerprint;
2178 }
2179 
setLocalFingerprint(fsfp_t fingerprint)2180 void SyncConfig::setLocalFingerprint(fsfp_t fingerprint)
2181 {
2182     mLocalFingerprint = fingerprint;
2183 }
2184 
getRegExps() const2185 const std::vector<std::string>& SyncConfig::getRegExps() const
2186 {
2187     return mRegExps;
2188 }
2189 
getType() const2190 SyncConfig::Type SyncConfig::getType() const
2191 {
2192     return mSyncType;
2193 }
2194 
isUpSync() const2195 bool SyncConfig::isUpSync() const
2196 {
2197     return mSyncType & TYPE_UP;
2198 }
2199 
isDownSync() const2200 bool SyncConfig::isDownSync() const
2201 {
2202     return mSyncType & TYPE_DOWN;
2203 }
2204 
syncDeletions() const2205 bool SyncConfig::syncDeletions() const
2206 {
2207     switch (mSyncType)
2208     {
2209         case TYPE_UP: return mSyncDeletions;
2210         case TYPE_DOWN: return mSyncDeletions;
2211         case TYPE_TWOWAY: return true;
2212     }
2213     assert(false);
2214     return true;
2215 }
2216 
forceOverwrite() const2217 bool SyncConfig::forceOverwrite() const
2218 {
2219     switch (mSyncType)
2220     {
2221         case TYPE_UP: return mForceOverwrite;
2222         case TYPE_DOWN: return mForceOverwrite;
2223         case TYPE_TWOWAY: return false;
2224     }
2225     assert(false);
2226     return false;
2227 }
2228 
2229 // This should be a const-method but can't be due to the broken Cacheable interface.
2230 // Do not mutate members in this function! Hence, we forward to a private const-method.
serialize(std::string * data)2231 bool SyncConfig::serialize(std::string* data)
2232 {
2233     return const_cast<const SyncConfig*>(this)->serialize(*data);
2234 }
2235 
unserialize(const std::string & data)2236 std::unique_ptr<SyncConfig> SyncConfig::unserialize(const std::string& data)
2237 {
2238     bool resumable;
2239     std::string localPath;
2240     handle remoteNode;
2241     fsfp_t fingerprint;
2242     uint32_t regExpCount;
2243     std::vector<std::string> regExps;
2244     uint32_t syncType;
2245     bool syncDeletions;
2246     bool forceOverwrite;
2247 
2248     CacheableReader reader{data};
2249     if (!reader.unserializebool(resumable))
2250     {
2251         return {};
2252     }
2253     if (!reader.unserializestring(localPath))
2254     {
2255         return {};
2256     }
2257     if (!reader.unserializehandle(remoteNode))
2258     {
2259         return {};
2260     }
2261     if (!reader.unserializefsfp(fingerprint))
2262     {
2263         return {};
2264     }
2265     if (!reader.unserializeu32(regExpCount))
2266     {
2267         return {};
2268     }
2269     for (uint32_t i = 0; i < regExpCount; ++i)
2270     {
2271         std::string regExp;
2272         if (!reader.unserializestring(regExp))
2273         {
2274             return {};
2275         }
2276         regExps.push_back(std::move(regExp));
2277     }
2278     if (!reader.unserializeu32(syncType))
2279     {
2280         return {};
2281     }
2282     if (!reader.unserializebool(syncDeletions))
2283     {
2284         return {};
2285     }
2286     if (!reader.unserializebool(forceOverwrite))
2287     {
2288         return {};
2289     }
2290 
2291     auto syncConfig = std::unique_ptr<SyncConfig>{new SyncConfig{std::move(localPath),
2292                     remoteNode, fingerprint, std::move(regExps),
2293                     static_cast<Type>(syncType), syncDeletions, forceOverwrite}};
2294     syncConfig->setResumable(resumable);
2295     return syncConfig;
2296 }
2297 
serialize(std::string & data) const2298 bool SyncConfig::serialize(std::string& data) const
2299 {
2300     CacheableWriter writer{data};
2301     writer.serializebool(mResumable);
2302     writer.serializestring(mLocalPath);
2303     writer.serializehandle(mRemoteNode);
2304     writer.serializefsfp(mLocalFingerprint);
2305     writer.serializeu32(static_cast<uint32_t>(mRegExps.size()));
2306     for (const auto& regExp : mRegExps)
2307     {
2308         writer.serializestring(regExp);
2309     }
2310     writer.serializeu32(static_cast<uint32_t>(mSyncType));
2311     writer.serializebool(mSyncDeletions);
2312     writer.serializebool(mForceOverwrite);
2313     writer.serializeexpansionflags();
2314     return true;
2315 }
2316 
operator ==(const SyncConfig & lhs,const SyncConfig & rhs)2317 bool operator==(const SyncConfig& lhs, const SyncConfig& rhs)
2318 {
2319     return lhs.tie() == rhs.tie();
2320 }
2321 
generateMetaMac(SymmCipher & cipher,FileAccess & ifAccess,const int64_t iv)2322 std::pair<bool, int64_t> generateMetaMac(SymmCipher &cipher, FileAccess &ifAccess, const int64_t iv)
2323 {
2324     FileInputStream isAccess(&ifAccess);
2325 
2326     return generateMetaMac(cipher, isAccess, iv);
2327 }
2328 
generateMetaMac(SymmCipher & cipher,InputStreamAccess & isAccess,const int64_t iv)2329 std::pair<bool, int64_t> generateMetaMac(SymmCipher &cipher, InputStreamAccess &isAccess, const int64_t iv)
2330 {
2331     static const m_off_t SZ_1024K = 1l << 20;
2332     static const m_off_t SZ_128K  = 128l << 10;
2333 
2334     std::unique_ptr<byte[]> buffer(new byte[SZ_1024K + SymmCipher::BLOCKSIZE]);
2335     chunkmac_map chunkMacs;
2336     m_off_t chunkLength = 0;
2337     m_off_t current = 0;
2338     m_off_t remaining = isAccess.size();
2339 
2340     while (remaining > 0)
2341     {
2342         chunkLength =
2343           std::min(chunkLength + SZ_128K,
2344                    std::min(remaining, SZ_1024K));
2345 
2346         if (!isAccess.read(&buffer[0], (unsigned int)chunkLength))
2347             return std::make_pair(false, 0l);
2348 
2349         memset(&buffer[chunkLength], 0, SymmCipher::BLOCKSIZE);
2350 
2351         cipher.ctr_crypt(&buffer[0],
2352                          (unsigned int)chunkLength,
2353                          current,
2354                          iv,
2355                          chunkMacs[current].mac,
2356                          1);
2357 
2358         current += chunkLength;
2359         remaining -= chunkLength;
2360     }
2361 
2362     return std::make_pair(true, chunkMacs.macsmac(&cipher));
2363 }
2364 
push(std::function<void (SymmCipher &)> f,bool discardable)2365 void MegaClientAsyncQueue::push(std::function<void(SymmCipher&)> f, bool discardable)
2366 {
2367     if (mThreads.empty())
2368     {
2369         if (f)
2370         {
2371             f(mZeroThreadsCipher);
2372         }
2373     }
2374     else
2375     {
2376         {
2377             std::lock_guard<std::mutex> g(mMutex);
2378             mQueue.emplace_back(discardable, std::move(f));
2379         }
2380         mConditionVariable.notify_one();
2381     }
2382 }
2383 
MegaClientAsyncQueue(Waiter & w,unsigned threadCount)2384 MegaClientAsyncQueue::MegaClientAsyncQueue(Waiter& w, unsigned threadCount)
2385     : mWaiter(w)
2386 {
2387     for (int i = threadCount; i--; )
2388     {
2389         try
2390         {
2391             mThreads.emplace_back([this]()
2392             {
2393                 asyncThreadLoop();
2394             });
2395         }
2396         catch (std::system_error& e)
2397         {
2398             LOG_err << "Failed to start worker thread: " << e.what();
2399             break;
2400         }
2401     }
2402     LOG_debug << "MegaClient Worker threads running: " << mThreads.size();
2403 }
2404 
~MegaClientAsyncQueue()2405 MegaClientAsyncQueue::~MegaClientAsyncQueue()
2406 {
2407     clearDiscardable();
2408     push(nullptr, false);
2409     mConditionVariable.notify_all();
2410     LOG_warn << "~MegaClientAsyncQueue() joining threads";
2411     for (auto& t : mThreads)
2412     {
2413         t.join();
2414     }
2415     LOG_warn << "~MegaClientAsyncQueue() ends";
2416 }
2417 
clearDiscardable()2418 void MegaClientAsyncQueue::clearDiscardable()
2419 {
2420     std::lock_guard<std::mutex> g(mMutex);
2421     auto newEnd = std::remove_if(mQueue.begin(), mQueue.end(), [](Entry& entry){ return entry.discardable; });
2422     mQueue.erase(newEnd, mQueue.end());
2423 }
2424 
asyncThreadLoop()2425 void MegaClientAsyncQueue::asyncThreadLoop()
2426 {
2427     SymmCipher cipher;
2428     for (;;)
2429     {
2430         std::function<void(SymmCipher&)> f;
2431         {
2432             std::unique_lock<std::mutex> g(mMutex);
2433             mConditionVariable.wait(g, [this]() { return !mQueue.empty(); });
2434             f = std::move(mQueue.front().f);
2435             if (!f) return;   // nullptr is not popped, and causes all the threads to exit
2436             mQueue.pop_front();
2437         }
2438         f(cipher);
2439         mWaiter.notify();
2440     }
2441 }
2442 
2443 } // namespace
2444 
2445