bitmap_loader_pbm.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*************************************************************************/
  2. /* bitmap_loader_pbm.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "bitmap_loader_pbm.h"
  30. #include "os/file_access.h"
  31. #include "scene/resources/bit_mask.h"
  32. static bool _get_token(FileAccessRef& f,uint8_t &saved,PoolVector<uint8_t>& r_token,bool p_binary=false,bool p_single_chunk=false) {
  33. int token_max = r_token.size();
  34. PoolVector<uint8_t>::Write w;
  35. if (token_max)
  36. w=r_token.write();
  37. int ofs=0;
  38. bool lf=false;
  39. while(true) {
  40. uint8_t b;
  41. if (saved) {
  42. b=saved;
  43. saved=0;
  44. } else {
  45. b = f->get_8();
  46. }
  47. if (f->eof_reached()) {
  48. if (ofs) {
  49. w=PoolVector<uint8_t>::Write();
  50. r_token.resize(ofs);
  51. return true;
  52. } else {
  53. return false;
  54. }
  55. }
  56. if (!ofs && !p_binary && b=='#') {
  57. //skip comment
  58. while(b!='\n') {
  59. if (f->eof_reached()) {
  60. return false;
  61. }
  62. b = f->get_8();
  63. }
  64. lf=true;
  65. } else if (b<=32 && !(p_binary && (ofs || lf))) {
  66. if (b=='\n') {
  67. lf=true;
  68. }
  69. if (ofs && !p_single_chunk) {
  70. w=PoolVector<uint8_t>::Write();
  71. r_token.resize(ofs);
  72. saved=b;
  73. return true;
  74. }
  75. } else {
  76. bool resized=false;
  77. while (ofs>=token_max) {
  78. if (token_max)
  79. token_max<<=1;
  80. else
  81. token_max=1;
  82. resized=true;
  83. }
  84. if (resized) {
  85. w=PoolVector<uint8_t>::Write();
  86. r_token.resize(token_max);
  87. w=r_token.write();
  88. }
  89. w[ofs++]=b;
  90. }
  91. }
  92. return false;
  93. }
  94. static int _get_number_from_token(PoolVector<uint8_t>& r_token) {
  95. int len = r_token.size();
  96. PoolVector<uint8_t>::Read r = r_token.read();
  97. return String::to_int((const char*)r.ptr(),len);
  98. }
  99. RES ResourceFormatPBM::load(const String &p_path,const String& p_original_path,Error *r_error) {
  100. #define _RETURN(m_err)\
  101. {\
  102. if (r_error)\
  103. *r_error=m_err;\
  104. ERR_FAIL_V(RES());\
  105. }
  106. FileAccessRef f=FileAccess::open(p_path,FileAccess::READ);
  107. uint8_t saved=0;
  108. if (!f)
  109. _RETURN(ERR_CANT_OPEN);
  110. PoolVector<uint8_t> token;
  111. if (!_get_token(f,saved,token)) {
  112. _RETURN(ERR_PARSE_ERROR);
  113. }
  114. if (token.size()!=2) {
  115. _RETURN(ERR_FILE_CORRUPT);
  116. }
  117. if (token[0]!='P') {
  118. _RETURN(ERR_FILE_CORRUPT);
  119. }
  120. if (token[1]!='1' && token[1]!='4') {
  121. _RETURN(ERR_FILE_CORRUPT);
  122. }
  123. bool bits = token[1]=='4';
  124. if (!_get_token(f,saved,token)) {
  125. _RETURN(ERR_PARSE_ERROR);
  126. }
  127. int width = _get_number_from_token(token);
  128. if (width<=0) {
  129. _RETURN(ERR_FILE_CORRUPT);
  130. }
  131. if (!_get_token(f,saved,token)) {
  132. _RETURN(ERR_PARSE_ERROR);
  133. }
  134. int height = _get_number_from_token(token);
  135. if (height<=0) {
  136. _RETURN(ERR_FILE_CORRUPT);
  137. }
  138. Ref<BitMap> bm;
  139. bm.instance();
  140. bm->create(Size2i(width,height));
  141. if (!bits) {
  142. int required_bytes = width*height;
  143. if (!_get_token(f,saved,token,false,true)) {
  144. _RETURN(ERR_PARSE_ERROR);
  145. }
  146. if (token.size()<required_bytes) {
  147. _RETURN(ERR_FILE_CORRUPT);
  148. }
  149. PoolVector<uint8_t>::Read r=token.read();
  150. for(int i=0;i<height;i++) {
  151. for(int j=0;j<width;j++) {
  152. char num = r[i*width+j];
  153. bm->set_bit(Point2i(j,i),num=='0');
  154. }
  155. }
  156. } else {
  157. //a single, entire token of bits!
  158. if (!_get_token(f,saved,token,true)) {
  159. _RETURN(ERR_PARSE_ERROR);
  160. }
  161. int required_bytes = Math::ceil((width*height)/8.0);
  162. if (token.size()<required_bytes) {
  163. _RETURN(ERR_FILE_CORRUPT);
  164. }
  165. PoolVector<uint8_t>::Read r=token.read();
  166. int bitwidth = width;
  167. if (bitwidth % 8)
  168. bitwidth+=8-(bitwidth%8);
  169. for(int i=0;i<height;i++) {
  170. for(int j=0;j<width;j++) {
  171. int ofs = bitwidth*i+j;
  172. uint8_t byte = r[ofs/8];
  173. bool bit = (byte>>(7-(ofs%8)))&1;
  174. bm->set_bit(Point2i(j,i),!bit);
  175. }
  176. }
  177. }
  178. return bm;
  179. }
  180. void ResourceFormatPBM::get_recognized_extensions(List<String> *p_extensions) const {
  181. p_extensions->push_back("pbm");
  182. }
  183. bool ResourceFormatPBM::handles_type(const String& p_type) const {
  184. return p_type=="BitMap";
  185. }
  186. String ResourceFormatPBM::get_resource_type(const String &p_path) const {
  187. if (p_path.get_extension().to_lower()=="pbm")
  188. return "BitMap";
  189. return "";
  190. }