11 #include <sys/time.h>
\r
16 #include <Raym/Log.h>
\r
17 #include <Raym/String.h>
\r
18 #include <Raym/Array.h>
\r
19 #include <Raym/Data.h>
\r
21 #define HEX2DEC(P1) (('a' <= P1) && (P1 <= 'f') ? (P1 - 'a' + 10) : ('A' <= P1) && (P1 <= 'F') ? (P1 - 'A' + 10) : ('0' <= P1) && (P1 <= '9') ? (P1 - '0') : 0)
\r
26 String *String::alloc()
\r
28 DebugLog2("String::alloc()");
\r
30 return new String();
\r
33 String *String::string()
\r
35 DebugLog2("String::string()");
\r
37 String *result = String::alloc()->init();
\r
40 result->autorelease();
\r
45 String *String::stringWithCString(const char *nullTerminatedCString, StringEncoding encoding)
\r
47 DebugLog2("String::stringWithCString()");
\r
49 String *result = String::alloc()->initWithCString(nullTerminatedCString, encoding);
\r
52 result->autorelease();
\r
57 String *String::stringWithUTF8String(const char *nullTerminatedCString)
\r
59 DebugLog2("String::stringWithUTF8String()");
\r
61 String *result = String::alloc()->initWithUTF8String(nullTerminatedCString);
\r
64 result->autorelease();
\r
69 String *String::stringWithFormat(String *format, ...)
\r
71 DebugLog2("String::stringWithFormat(String *, ...)");
\r
73 String *result = NULL;
\r
77 va_start(ap, format);
\r
78 result = String::alloc()->initWithFormat(format->cString(), ap);
\r
82 result->autorelease();
\r
88 String *String::stringWithFormat(const char *format, ...)
\r
90 DebugLog2("String::stringWithFormat(const char *, ...)");
\r
92 String *result = NULL;
\r
96 va_start(ap, format);
\r
97 result = String::alloc()->initWithFormat(format, ap);
\r
101 result->autorelease();
\r
107 String *String::stringWithContentsOfFile(const char *path, StringEncoding encoding)
\r
109 DebugLog2("String::stringWithContentsOfFile()");
\r
111 String *result = NULL;
\r
114 Data *data = Data::dataWithContentsOfFile(path);
\r
118 char *tmp = (char *)malloc(data->length() + 1);
\r
121 memcpy(tmp, data->bytes(), data->length());
\r
122 tmp[data->length()] = '\0';
\r
123 result = String::stringWithUTF8String(tmp);
\r
127 result = String::alloc()->initWithData(data, encoding);
\r
128 if (result != NULL)
\r
130 result->autorelease();
\r
138 String *String::stringWithString(String *string)
\r
140 DebugLog2("String::stringWithString()");
\r
142 String *result = NULL;
\r
143 if (string != NULL)
\r
145 result = String::alloc()->initWithUTF8String(string->cString());
\r
146 if (result != NULL)
\r
148 result->autorelease();
\r
154 String *String::base64StringWithBytes(const char *bytes, UInteger length)
\r
156 DebugLog2("String::base64StringWithBytes()");
\r
158 static char base64EncodingTable[64] =
\r
160 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
\r
161 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
\r
162 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
\r
163 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
\r
172 return String::string();
\r
175 unsigned long long buflen = ((length + 3) / 3) * 4 + 1;
\r
176 char *encoded = (char *)malloc(buflen);
\r
177 if (encoded == NULL)
\r
181 encoded[buflen - 1] = '\0';
\r
183 unsigned long long in_offset = 0;
\r
184 unsigned long long out_offset = 0;
\r
185 while (in_offset < length)
\r
187 switch (length - in_offset)
\r
190 encoded[out_offset] = base64EncodingTable[(bytes[in_offset] & 0xFC) >> 2];
\r
191 encoded[out_offset + 1] = base64EncodingTable[((bytes[in_offset] & 0x03) << 4)];
\r
192 encoded[out_offset + 2] = '=';
\r
193 encoded[out_offset + 3] = '=';
\r
196 encoded[out_offset] = base64EncodingTable[(bytes[in_offset] & 0xFC) >> 2];
\r
197 encoded[out_offset + 1] = base64EncodingTable[((bytes[in_offset] & 0x03) << 4) | ((bytes[in_offset + 1] & 0xF0) >> 4)];
\r
198 encoded[out_offset + 2] = base64EncodingTable[((bytes[in_offset + 1] & 0x0F) << 2)];
\r
199 encoded[out_offset + 3] = '=';
\r
202 encoded[out_offset] = base64EncodingTable[(bytes[in_offset] & 0xFC) >> 2];
\r
203 encoded[out_offset + 1] = base64EncodingTable[((bytes[in_offset] & 0x03) << 4) | ((bytes[in_offset + 1] & 0xF0) >> 4)];
\r
204 encoded[out_offset + 2] = base64EncodingTable[((bytes[in_offset + 1] & 0x0F) << 2) | ((bytes[in_offset + 2] & 0xC0) >> 6)];
\r
205 encoded[out_offset + 3] = base64EncodingTable[bytes[in_offset + 2] & 0x3F];
\r
212 String *result = String::stringWithUTF8String(encoded);
\r
220 DebugLog2("String::String()");
\r
228 DebugLog2("String::~String(\"%s\")", _str);
\r
238 String *String::init()
\r
240 DebugLog2("String::init()");
\r
242 _str = (char *)malloc(1);
\r
253 String *String::initWithCString(const char *nullTerminatedCString, StringEncoding encoding)
\r
255 DebugLog2("String::initWithCString(\"%s\", %d)", nullTerminatedCString, encoding);
\r
257 if (nullTerminatedCString != NULL)
\r
259 UInteger length = (UInteger)strlen(nullTerminatedCString);
\r
264 case ShiftJISStringEncoding:
\r
267 int wlen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, nullTerminatedCString, (int)(strlen(nullTerminatedCString) + 1), NULL, 0);
\r
270 wchar_t *wbuf = (wchar_t *)malloc(sizeof(wchar_t) * (wlen + 1));
\r
273 memset(wbuf, 0x00, sizeof(wchar_t) * (wlen + 1));
\r
274 MultiByteToWideChar(CP_ACP, 0, nullTerminatedCString, (int)(strlen(nullTerminatedCString) + 1), wbuf, sizeof(wchar_t) * (wlen + 1));
\r
275 int ulen = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL, NULL);
\r
278 _str = (char *)malloc(ulen + 1);
\r
281 memset(_str, 0x00, ulen + 1);
\r
282 WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, _str, ulen + 1, NULL, NULL);
\r
288 DebugLog0("error: %s(): malloc", __FUNCTION__);
\r
296 DebugLog0("error: %s(): WideCharToMultiByte", __FUNCTION__);
\r
303 DebugLog0("error: %s(): malloc", __FUNCTION__);
\r
310 DebugLog0("error: %s(): MultiByteToWideChar, 0x%08x", __FUNCTION__, GetLastError());
\r
315 DebugLog0("not implement.");
\r
320 case UTF8StringEncoding:
\r
321 _str = (char *)malloc(length + 1);
\r
325 memcpy(_str, nullTerminatedCString, _length);
\r
326 _str[_length] = '\0';
\r
330 DebugLog3("error: %s(): malloc", __FUNCTION__);
\r
337 DebugLog0("warning: Unknown String Encoding: 0x%08x", encoding);
\r
350 DebugLog0("warning: string is null.");
\r
358 String *String::initWithUTF8String(const char *bytes)
\r
360 DebugLog2("String::initWithUTF8String()");
\r
362 return initWithCString(bytes, UTF8StringEncoding);
\r
365 String *String::initWithData(Data *data, StringEncoding encoding)
\r
367 DebugLog2("String::initWithData()");
\r
369 String *result = NULL;
\r
372 char *tmp = (char *)malloc(data->length() + 1);
\r
375 memcpy(tmp, data->bytes(), data->length());
\r
376 tmp[data->length()] = '\0';
\r
377 result = String::initWithCString(tmp, encoding);
\r
383 DebugLog0("warning: data is null.");
\r
390 String *String::initWithFormat(const char *format, ...)
\r
392 DebugLog2("String::initWithFormat(const char *, ...)");
\r
394 if (format == NULL)
\r
401 va_start(ap, format);
\r
402 String *result = initWithFormat(format, ap);
\r
409 // format(書式は1つのみ)とvalueで、新たにmallocした領域にsnprintfして返す。
\r
410 // 呼び元はfreeすること。malloc失敗等の場合はNULLを返す。
\r
412 static char *print_1(const char *format, void *value)
\r
414 static const int DEFAULT_LENGTH = 32;
\r
415 char *buf = (char *)malloc(DEFAULT_LENGTH);
\r
419 int require = _snprintf_s(buf, DEFAULT_LENGTH, _TRUNCATE, format, value);
\r
421 int require = snprintf(buf, DEFAULT_LENGTH, format, value);
\r
423 if (require >= DEFAULT_LENGTH)
\r
426 char *buf2 = (char *)realloc(buf, require);
\r
431 _snprintf_s(buf, require, _TRUNCATE, format, value);
\r
433 snprintf(buf, require, format, value);
\r
447 // allocしたs1をs2分加算してreallocしてstrcatし、新しい(または同じ)アドレスを返す。
\r
448 // 失敗した場合はNULLを返す。その場合 s1 は解放はしない。
\r
449 static char *strcat_with_realloc(char *s1, const char *s2)
\r
451 char *buf = (char *)realloc(s1, strlen(s1) + strlen(s2) + 1);
\r
454 strcat_s(buf, (strlen(s1) + strlen(s2) + 1), s2);
\r
459 String *String::initWithFormat(const char *format, va_list ap)
\r
461 DebugLog2("String::initWithFormat(const char *, va_list)");
\r
468 printf("initWithFormat: format: %s\n", format);
\r
469 void *p = va_arg(ap2, void *);
\r
470 printf("initWithFormat: arg1: 0x%016lx\n", p);
\r
475 if (strstr(format, "%@") == NULL)
\r
477 // とりあえず 256バイトくらいで実行してみて
\r
478 #define INITIAL_LENGTH 256
\r
479 buf = (char *)malloc(INITIAL_LENGTH);
\r
482 DebugLog3("malloc NG. (1)\n");
\r
491 int result = vsnprintf_s(buf, INITIAL_LENGTH, INITIAL_LENGTH - 1, format, ap);
\r
498 char *buf2 = (char *)realloc(buf, INITIAL_LENGTH * count);
\r
501 DebugLog3("realloc NG. (1)\n");
\r
508 result = vsnprintf_s(buf, INITIAL_LENGTH * count, INITIAL_LENGTH * count - 1, format, ap2);
\r
509 if (result >= INITIAL_LENGTH)
\r
518 int require = vsnprintf(buf, INITIAL_LENGTH, format, ap);
\r
521 if (require >= INITIAL_LENGTH)
\r
525 char *buf2 = (char *)realloc(buf, require);
\r
528 DebugLog3("realloc NG. (1)\n");
\r
535 vsnprintf(buf, require, format, ap2);
\r
542 // windows で動かしたら %@ がうまくいかないので
\r
544 printf("%%@ tu ka e nai\n");
\r
548 char *fmt = _strdup(format);
\r
550 char *fmt = strdup(format);
\r
554 DebugLog3("strdup NG.\n");
\r
560 buf = (char *)malloc(1);
\r
563 DebugLog3("malloc NG. (2)\n");
\r
573 if (strlen(p1) == 0)
\r
577 p2 = strchr(p1 + 1, '%');
\r
583 buf = (char *)realloc(buf, strlen(buf) + 1 + 2);
\r
586 DebugLog3("realloc NG. (2)\n");
\r
591 strcat_s(buf, (strlen(buf) + 3), "%%");
\r
597 if (strstr(p1, "%") != NULL)
\r
601 if ((at = strstr(p1, "%@")) != NULL)
\r
605 Object *obj = va_arg(ap, Object *);
\r
606 ptr = (void *)obj->description()->cString();
\r
610 ptr = va_arg(ap, void *);
\r
613 char *tmpbuf = print_1(p1, ptr);
\r
614 if (tmpbuf == NULL)
\r
621 char *buf2 = strcat_with_realloc(buf, tmpbuf);
\r
634 char *buf2 = strcat_with_realloc(buf, p1);
\r
653 void *ptr = (void *)"(nil)";
\r
655 if ((at = strstr(p1, "%@")) != NULL)
\r
659 Object *obj = va_arg(ap, Object *);
\r
662 ptr = (void *)obj->description()->cString();
\r
667 ptr = va_arg(ap, void *);
\r
669 char *tmpbuf = print_1(p1, ptr);
\r
670 if (tmpbuf == NULL)
\r
677 char *buf2 = strcat_with_realloc(buf, tmpbuf);
\r
690 char *buf2 = strcat_with_realloc(buf, p1);
\r
706 String *result= initWithUTF8String(buf);
\r
712 String *String::retain()
\r
714 DebugLog2("String::retain()");
\r
720 String *String::autorelease()
\r
722 DebugLog2("String::autorelease()");
\r
724 Object::autorelease();
\r
728 UInteger String::length()
\r
730 DebugLog2("String::length()");
\r
735 bool String::hasPrefix(String *prefix)
\r
737 bool result = false;
\r
738 if (prefix != NULL)
\r
740 if (length() >= prefix->length())
\r
742 result = (strncmp(_str, prefix->_str, prefix->length()) == 0);
\r
748 bool String::hasPrefix(const char *prefix)
\r
750 DebugLog2("String::hasPrefix()");
\r
752 String *k = String::alloc()->initWithUTF8String(prefix);
\r
753 bool ret = hasPrefix(k);
\r
758 bool String::hasSuffix(String *suffix)
\r
760 bool result = false;
\r
761 if (suffix != NULL)
\r
763 if (length() >= suffix->length())
\r
765 result = (strncmp(&_str[length() - suffix->length()], suffix->_str, suffix->length()) == 0);
\r
771 bool String::hasSuffix(const char *suffix)
\r
773 DebugLog3("String::hasSuffix()");
\r
775 String *k = String::alloc()->initWithUTF8String(suffix);
\r
776 bool ret = hasSuffix(k);
\r
781 bool String::isEqualToString(String *string)
\r
783 DebugLog3("String::isEqualToString(\"%s\")", string->cString());
\r
785 bool result = false;
\r
786 if (string != NULL)
\r
788 result = (strcmp(_str, string->_str) == 0);
\r
793 bool String::isEqualToString(const char *string)
\r
795 DebugLog3("String::isEqualToString(\"%s\")", string);
\r
797 String *k = String::alloc()->initWithCString(string, UTF8StringEncoding);
\r
798 bool ret = isEqualToString(k);
\r
803 bool String::isMatch(String *regex)
\r
805 DebugLog3("String::isMatch()");
\r
807 bool result = false;
\r
811 std::regex re(regex->cString());
\r
812 std::match_results<const char *>results;
\r
814 result = std::regex_search(_str, results, re, std::regex_constants::match_default);
\r
819 result = isMatch(regex->cString());
\r
825 bool String::isMatch(const char *regex)
\r
827 DebugLog3("String::isMatch()");
\r
829 bool result = false;
\r
832 std::regex re(regex);
\r
833 std::match_results<const char *>results;
\r
835 result = std::regex_search(_str, results, re, std::regex_constants::match_default);
\r
840 String *String::stringByAppendingPathComponent(String *pathComponent)
\r
842 DebugLog3("String::stringByAppendingPathComponent()");
\r
844 String *result = NULL;
\r
845 if (pathComponent != NULL)
\r
847 Array *paths = pathComponent->pathComponents();
\r
850 if (paths->count() > 0)
\r
852 if (((String *)paths->objectAtIndex(0))->isEqualToString("/") ||
\r
853 ((String *)paths->objectAtIndex(0))->isEqualToString("\\"))
\r
855 paths->removeObjectAtIndex(0);
\r
857 if (paths->count() > 0)
\r
859 if (hasSuffix("/") || hasSuffix("\\"))
\r
861 result = stringByAppendingString((String *)paths->objectAtIndex(0));
\r
865 result = stringByAppendingString("\\");
\r
866 result = result->stringByAppendingString((String *)paths->objectAtIndex(0));
\r
868 paths->removeObjectAtIndex(0);
\r
869 if (paths->count() > 0)
\r
871 for (UInteger i = 0; i < paths->count(); ++i)
\r
873 result = result->stringByAppendingString("\\");
\r
874 result = result->stringByAppendingString((String *)paths->objectAtIndex(i));
\r
881 if (result == NULL)
\r
883 result = String::stringWithString(this);
\r
888 String *String::stringByAppendingPathComponent(const char *pathComponent)
\r
890 return stringByAppendingPathComponent(String::stringWithUTF8String(pathComponent));
\r
893 String *String::stringByAppendingString(String *aString)
\r
895 String *result = NULL;
\r
896 if (aString != NULL)
\r
898 result = String::stringWithFormat("%s%s", _str, aString->cString());
\r
903 String *String::stringByAppendingString(const char *aString)
\r
905 return stringByAppendingString(String::stringWithUTF8String(aString));
\r
908 String *String::stringByAbbreviatingWithTildeInPath()
\r
910 String *result = NULL;
\r
911 result = String::stringWithUTF8String(cString());
\r
915 String *String::stringByReplacingOccurrencesOfString(String *target, String *replacement)
\r
917 String *result = NULL;
\r
918 if ((target != NULL) && (replacement != NULL))
\r
920 std::string tmp = _str;
\r
921 while (strstr(tmp.c_str(), target->cString()) != NULL)
\r
923 tmp.replace(tmp.find(target->cString(), 0), target->length(), replacement->cString());
\r
925 result = String::stringWithUTF8String(tmp.c_str());
\r
927 if (result == NULL)
\r
929 result = String::stringWithUTF8String(_str);
\r
934 String *String::stringByReplacingOccurrencesOfString(const char *target, const char *replacement)
\r
936 return stringByReplacingOccurrencesOfString(String::stringWithUTF8String(target),
\r
937 String::stringWithUTF8String(replacement));
\r
940 String *String::stringByReplacingOccurrencesOfString(const char *target, String *replacement)
\r
942 return stringByReplacingOccurrencesOfString(String::stringWithUTF8String(target), replacement);
\r
945 String *String::stringByStandardizingPath()
\r
947 String *result = NULL;
\r
948 result = String::stringWithUTF8String(cString());
\r
952 String *String::stringByRemovingPercentEncoding()
\r
954 String *result = NULL;
\r
955 char *buf = (char *)malloc(_length + 1);
\r
964 *dst = (HEX2DEC(p[1]) << 4) | HEX2DEC(p[2]);
\r
965 DebugLog3("%02x", *dst);
\r
975 DebugLog3("buf: %s", buf);
\r
976 result = String::stringWithUTF8String(buf);
\r
981 result = String::string();
\r
986 String *String::stringByTrimming()
\r
988 String *result = NULL;
\r
989 char *buf = _strdup(_str);
\r
1006 if (st[strlen(st) - 1] == ' ')
\r
1008 st[strlen(st) - 1] = '\0';
\r
1015 result = String::stringWithUTF8String(st);
\r
1020 result = String::string();
\r
1025 Array *String::pathComponents()
\r
1027 Array *result = Array::arrayWithCapacity(0);
\r
1029 char *tmp = _strdup(_str);
\r
1031 char *tmp = strdup(_str);
\r
1036 if ((*p == '\\') || (*p == '/'))
\r
1038 result->addObject(String::stringWithUTF8String("\\"));
\r
1043 char *p2 = strchr(p, '\\');
\r
1046 p2 = strchr(p, '/');
\r
1052 if (strlen(p) > 0)
\r
1054 result->addObject(String::stringWithUTF8String(p));
\r
1071 String *String::pathExtension()
\r
1073 String *result = NULL;
\r
1074 Array *comps = pathComponents();
\r
1075 if (comps != NULL)
\r
1077 if (comps->count() > 0)
\r
1079 String *last = (String *)comps->objectAtIndex(comps->count() - 1);
\r
1080 char *p = strrchr(last->_str, '.');
\r
1083 result = String::stringWithUTF8String(++p);
\r
1087 if (result == NULL)
\r
1089 result = String::stringWithUTF8String("");
\r
1094 Array *String::componentsSeparatedByString(String *separator)
\r
1096 return componentsSeparatedByString(separator->cString());
\r
1099 Array *String::componentsSeparatedByString(const char *separator)
\r
1101 Array *result = Array::arrayWithCapacity(0);
\r
1102 char *tmp = _strdup(_str);
\r
1106 char *p2 = strstr(p1, separator);
\r
1110 result->addObject(String::stringWithUTF8String(p1));
\r
1111 p1 = p2 + strlen(separator);
\r
1115 result->addObject(String::stringWithUTF8String(p1));
\r
1123 String *String::substringFromIndex(UInteger anIndex)
\r
1125 String *result = NULL;
\r
1126 if (anIndex < _length)
\r
1128 result = String::stringWithUTF8String(&_str[anIndex]);
\r
1133 String *String::substringToIndex(UInteger anIndex)
\r
1135 String *result = NULL;
\r
1136 if (anIndex < _length)
\r
1138 char *tmp = _strdup(_str);
\r
1141 tmp[anIndex] = '\0';
\r
1142 result = String::stringWithUTF8String(tmp);
\r
1146 else if (anIndex == _length)
\r
1148 result = String::stringWithUTF8String(_str);
\r
1153 String *String::lowercaseString()
\r
1155 String *result = NULL;
\r
1157 char *tmp = _strdup(_str);
\r
1159 char *tmp = strdup(_str);
\r
1163 for (size_t idx = 0; idx < strlen(tmp); ++idx)
\r
1165 tmp[idx] = tolower(tmp[idx]);
\r
1167 result = String::stringWithUTF8String(tmp);
\r
1170 if (result == NULL)
\r
1172 result = String::stringWithUTF8String(_str);
\r
1177 Range String::rangeOfString(String *aString)
\r
1179 Range result = {NotFound, 0};
\r
1180 if (aString != NULL)
\r
1182 result = rangeOfString(aString->cString());
\r
1187 Range String::rangeOfString(const char *aString)
\r
1189 Range result = {NotFound, 0};
\r
1190 if (aString != NULL)
\r
1192 char *p = strstr(_str, aString);
\r
1195 result.location = (UInteger)(p - _str);
\r
1196 result.length = (UInteger)strlen(aString);
\r
1202 int String::intValue()
\r
1204 return atoi(_str);
\r
1207 const char *String::cString()
\r
1209 DebugLog2("String::cString()\n");
\r
1213 DebugLog3("why?\n");
\r
1219 const char *String::className()
\r
1224 String *String::description()
\r